cdncheck

repository·main·Indexed 21 days ago

https://github.com/projectdiscovery/cdncheck

A tool and Go library used to identify whether a given IP or DNS address is associated with a CDN, Cloud provider, or WAF. It provides a CLI for network address identification and a Go API featuring methods like CheckCDN, CheckCloud, CheckWAF, and CheckDomainWithFallback to detect provider associations via IP ranges, CNAME patterns, and Wappalyzer technology signatures.

Tokens
4.1K
Snippets
13
Records
15
Agent score
75%

What's inside cdncheck

  1. How to add CNAME or Wappalyzer based providers

    main

    For providers that rely on CNAME patterns or Wappalyzer technology signatures, you must modify the other.go file. Add the mapping to the cdnCnameDomains or cdnWappalyzerTechnologies variables.

    // cdnCnameDomains contains a map of CNAME to domains to cdns
    var cdnCnameDomains = map[string]string{
    	"cloudfront.net":         "amazon",
    	"amazonaws.com":          "amazon",
        ...
    }
    
    // cdnWappalyzerTechnologies contains a map of wappalyzer technologies to cdns
    var cdnWappalyzerTechnologies = map[string]string{
    	"imperva":    "imperva",
    	"incapsula":  "incapsula",
    	...
    }
  2. How to add new CDN, WAF, or Cloud providers

    main

    New providers can be added by modifying the cmd/generate-index/provider.yaml file. The file supports three types of provider definitions:

    1. ASN: A list of ASN numbers for the provider.
    2. URLs: A list of URLs that contain the provider's IP lists (to be scraped).
    3. CIDR: A list of static CIDR ranges.

    After updating provider.yaml, the data is compiled into sources_data.json using the generate-index program. To contribute, fork the repository, modify the YAML file in the cmd/generate-index directory, and submit a pull request.

    cdn:
      # asn contains the ASN numbers for providers
      asn:
        leaseweb:
          - AS60626
    
      # urls contains a list of URLs for CDN providers
      urls:
        cloudfront:
          - https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips
        fastly:
          - https://api.fastly.com/public-ip-list
    
      # cidr contains the CIDR ranges for providers
      cidr:
        akamai:
          - "23.235.32.0/20"
          - "43.249.72.0/22"
  3. Use cdncheck as a Go library

    main

    You can integrate cdncheck into your Go projects by importing github.com/projectdiscovery/cdncheck. Use cdncheck.New() to initialize a client, then use CheckCDN(ip), CheckCloud(ip), or CheckWAF(ip) to identify the technology associated with a given net.IP.

    package main
    
    import (
    	"fmt"
    	"net"
    	"github.com/projectdiscovery/cdncheck"
    )
    
    func main() {
    	client := cdncheck.New()
    	ip := net.ParseIP("173.245.48.12")
    
    	// checks if an IP is contained in the cdn denylist
    	matched, val, err := client.CheckCDN(ip)
    	if err != nil {
    		panic(err)
    	}
    
    	if matched {
    		fmt.Printf("%v is a %v\n", ip, val)
    	} else {
    		fmt.Printf("%v is not a CDN\n", ip)
    	}
    
    	// checks if an IP is contained in the cloud denylist
    	matched, val, err = client.CheckCloud(ip)
    	if err != nil {
    		panic(err)
    	}
    
    	if matched {
    		fmt.Printf("%v is a %v\n", ip, val)
    	} else {
    		fmt.Printf("%v is not a Cloud\n", ip)
    	}
    
    	// checks if an IP is contained in the waf denylist
    	matched, val, err = client.CheckWAF(ip)
    	if err != nil {
    		panic(err)
    	}
    
    	if matched {
    		fmt.Printf("%v WAF is %v\n", ip, val)
    	} else {
    		fmt.Printf("%v is not a WAF\n", ip)
    	}
    }
  4. Reference cdncheck CLI flags

    main

    The following flags are available for the cdncheck command line tool:

    INPUT:
       -i, -input string[]  list of ip / dns to process
    
    DETECTION:
       -cdn    display only cdn in cli output
       -cloud  display only cloud in cli output
       -waf    display only waf in cli output
    
    MATCHER:
       -mcdn, -match-cdn string[]      match host with specified cdn provider (cloudfront, fastly, google, leaseweb)
       -mcloud, -match-cloud string[]  match host with specified cloud provider (aws, google, oracle)
       -mwaf, -match-waf string[]      match host with specified waf provider (cloudflare, incapsula, sucuri, akamai)
    
    FILTER:
       -fcdn, -filter-cdn string[]      filter host with specified cdn provider (cloudfront, fastly, google, leaseweb)
       -fcloud, -filter-cloud string[]  filter host with specified cloud provider (aws, google, oracle)
       -fwaf, -filter-waf string[]      filter host with specified waf provider (cloudflare, incapsula, sucuri, akamai)
    
    OUTPUT:
       -resp               display technology name in cli output
       -o, -output string  write output in plain format to file
       -v, -verbose        display verbose output
       -j, -jsonl          write output in json(line) format
       -nc, -no-color      disable colors in cli output
       -version            display version of the project
       -silent             only display results in output
    
    CONFIG:
       -r, -resolver string[]  list of resolvers to use (file or comma separated)
       -e, -exclude            exclude detected ip from output
       -retry int              maximum number of retries for dns resolution (must be at least 1) (default 2)
    
    UPDATE:
       -up, -update                 update cdncheck to latest version
       -duc, -disable-update-check  disable automatic cdncheck update check
  5. Check if FQDNs belong to known CDN/WAF providers using CheckSuffix

    main

    The CheckSuffix method on the Client struct determines if one or more Fully Qualified Domain Names (FQDNs) are associated with known CDN or WAF providers by inspecting their suffixes (TLD or SLD+TLD).

    If a match is found, it returns itemType as "waf". This method uses the publicsuffix library to parse domains and relies on generatedData.Common to map suffixes to providers.

    isCDN, provider, itemType, err := client.CheckSuffix("example.cloudflare.com", "another.incapsula.com")
    if err != nil {
        // handle error
    }
    if isCDN {
        fmt.Printf("Detected %s provider via %s (type: %s)\n", provider, itemType)
    }
  6. Check DNS responses for provider matches

    main

    If you have already performed DNS resolution and have a *retryabledns.DNSData object, you can pass it directly to CheckDNSResponse to avoid redundant network calls.

    func (c *Client) CheckDNSResponse(dnsResponse *retryabledns.DNSData) (matched bool, value string, itemType string, err error)

    This method iterates through AAAA records, then A records, and finally checks CNAME suffixes to find a match in the provider denylists.

  7. Check a domain name with DNS fallback

    main

    The CheckDomainWithFallback method allows you to check if a domain name is associated with a CDN, WAF, or Cloud provider. It performs the following steps:

    1. Resolves the domain to get DNS records (A, AAAA, etc.).
    2. Checks the resulting IP addresses against the provider denylists.
    3. If no match is found, it attempts to resolve the CNAME records and checks those as well.

    func (c *Client) CheckDomainWithFallback(domain string) (matched bool, value string, itemType string, err error)

    Returns:

    • matched: true if the domain (or its CNAME) resolves to a known provider.
    • value: The name of the provider.
    • itemType: The category ("cdn", "waf", or "cloud").
    • err: Error if DNS resolution or checking fails.
    matched, value, itemType, err := client.CheckDomainWithFallback("example.com")
    if err == nil && matched {
        fmt.Printf("Domain is behind %s (%s)\n", value, itemType)
    }
  8. Check Wappalyzer technology detections using CheckWappalyzer

    main

    The CheckWappalyzer method on the Client struct checks if a set of Wappalyzer technology detections corresponds to a known CDN provider.

    It accepts a map[string]struct{} representing the detected technologies. The method handles technology strings that may contain colons (e.g., technology:version) by stripping the version part and performing a case-insensitive lookup against a built-in map of CDN technologies.

    Supported technologies include:

    • imperva
    • incapsula
    • cloudflare
    • cloudfront (maps to amazon)
    • akamai
    // Example: simulating Wappalyzer technology detections
    detections := map[string]struct{}{
        "Cloudflare:1.0": {},
        "other-tech":      {},
    }
    
    isCDN, provider, err := client.CheckWappalyzer(detections)
    if err != nil {
        // handle error
    }
    if isCDN {
        fmt.Printf("Detected CDN provider: %s\n", provider)
    }
  9. Initialize a cdncheck Client

    main

    To use cdncheck as a library, you should create a Client instance. While New() provides a client with default settings, it is recommended to use NewWithOpts() to configure custom retry logic and DNS resolvers.

    NewWithOpts(MaxRetries int, resolvers []string)

    • MaxRetries: The number of times to retry DNS queries. If set to 0 or less, it defaults to 3.
    • resolvers: A slice of DNS resolver addresses (e.g., []string{"8.8.8.8:53"}). If empty, it uses DefaultResolvers (which includes IPv4 and potentially IPv6 resolvers depending on connectivity).
    package main
    
    import (
    	"fmt"
    	"net"
    	"github.com/projectdiscovery/cdncheck"
    )
    
    func main() {
    	// Recommended: Initialize with custom options
    	client, err := cdncheck.NewWithOpts(3, []string{"1.1.1.1:53"})
    	if err != nil {
    		panic(err)
    	}
    
    	// Use the client to check an IP
    	ip := net.ParseIP("1.0.0.1")
    	matched, value, err := client.CheckCDN(ip)
    	if err == nil && matched {
    		fmt.Printf("IP belongs to CDN: %s\n", value)
    	}
    }
  10. Check if an IP belongs to CDN, WAF, or Cloud providers

    main

    The Check method is a generic way to determine if a given net.IP is part of a known CDN, WAF, or Cloud provider denylist.

    func (c *Client) Check(ip net.IP) (matched bool, value string, itemType string, err error)

    Returns:

    • matched: true if the IP is found in any denylist.
    • value: The name of the provider (e.g., "Cloudflare").
    • itemType: A string identifying the category: "cdn", "waf", or "cloud".
    • err: Any error encountered during the lookup.
    matched, value, itemType, err := client.Check(net.ParseIP("1.0.0.1"))
    if err == nil && matched {
        fmt.Printf("Found %s: %s (Type: %s)\n", value, itemType)
    }