Skip to content

Commit 6b4cdc0

Browse files
authored
Merge pull request #16 from projectdiscovery/expose-provider
Expose provider name in check cidr function
2 parents 725332c + 5898f29 commit 6b4cdc0

File tree

6 files changed

+181
-63
lines changed

6 files changed

+181
-63
lines changed

cdn-server/main.go

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"flag"
8+
"log"
9+
"net/http"
10+
"sync"
11+
"time"
12+
13+
"github.com/projectdiscovery/cdncheck"
14+
)
15+
16+
var (
17+
cdncheckData []byte
18+
cdncehckDataMutex = &sync.RWMutex{}
19+
20+
addr = flag.String("addr", "127.0.0.1:80", "Address to listen cdncheck server on")
21+
)
22+
23+
func main() {
24+
flag.Parse()
25+
26+
var cancel context.CancelFunc
27+
go func() {
28+
cancel = cdncheckWorker()
29+
}()
30+
cdncheckRefreshDataFunc()
31+
32+
http.HandleFunc("/", cdncheckHandler)
33+
if err := http.ListenAndServe(*addr, http.DefaultServeMux); err != nil {
34+
cancel()
35+
panic(err)
36+
}
37+
}
38+
39+
func cdncheckWorker() context.CancelFunc {
40+
ctx, cancel := context.WithCancel(context.Background())
41+
42+
ticker := time.NewTicker(24 * time.Hour)
43+
go func() {
44+
for {
45+
select {
46+
case <-ticker.C:
47+
cdncheckRefreshDataFunc()
48+
case <-ctx.Done():
49+
ticker.Stop()
50+
return
51+
default:
52+
continue
53+
}
54+
}
55+
}()
56+
return cancel
57+
}
58+
59+
func cdncheckRefreshDataFunc() {
60+
log.Printf("[%s] Refreshing cdncheck data from providers\n", time.Now().String())
61+
62+
client, err := cdncheck.New()
63+
if err != nil {
64+
log.Printf("[err] could not create cdncheck client: %s\n", err)
65+
return
66+
}
67+
data := client.Ranges()
68+
69+
var buf bytes.Buffer
70+
if err := json.NewEncoder(&buf).Encode(data); err != nil {
71+
log.Printf("[err] could not json encode cdn data: %s\n", err)
72+
return
73+
}
74+
75+
cdncehckDataMutex.Lock()
76+
cdncheckData = buf.Bytes()
77+
cdncehckDataMutex.Unlock()
78+
}
79+
80+
func cdncheckHandler(w http.ResponseWriter, r *http.Request) {
81+
cdncehckDataMutex.RLock()
82+
data := cdncheckData
83+
cdncehckDataMutex.RUnlock()
84+
85+
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
86+
_, _ = w.Write(data)
87+
}

cdncheck.go

+75-47
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,17 @@ import (
1212
// Client checks for CDN based IPs which should be excluded
1313
// during scans since they belong to third party firewalls.
1414
type Client struct {
15-
Options Options
16-
Data map[string]struct{}
17-
ranger cidranger.Ranger
15+
Options *Options
16+
ranges map[string][]string
17+
rangers map[string]cidranger.Ranger
1818
}
1919

2020
var defaultScrapers = map[string]scraperFunc{
21-
// "akamai": scrapeAkamai,
2221
"azure": scrapeAzure,
2322
"cloudflare": scrapeCloudflare,
2423
"cloudfront": scrapeCloudFront,
2524
"fastly": scrapeFastly,
2625
"incapsula": scrapeIncapsula,
27-
// "sucuri": scrapeSucuri,
28-
// "leaseweb": scrapeLeaseweb,
2926
}
3027

3128
var defaultScrapersWithOptions = map[string]scraperWithOptionsFunc{
@@ -34,10 +31,6 @@ var defaultScrapersWithOptions = map[string]scraperWithOptionsFunc{
3431
"leaseweb": scrapeLeaseweb,
3532
}
3633

37-
var cachedScrapers = map[string]scraperFunc{
38-
"projectdiscovery": scrapeProjectDiscovery,
39-
}
40-
4134
// New creates a new firewall IP checking client.
4235
func New() (*Client, error) {
4336
return new(&Options{})
@@ -65,60 +58,95 @@ func new(options *Options) (*Client, error) {
6558
},
6659
Timeout: time.Duration(30) * time.Second,
6760
}
68-
client := &Client{}
61+
client := &Client{Options: options}
6962

63+
var err error
7064
if options.Cache {
71-
for _, scraper := range cachedScrapers {
72-
cidrs, err := scraper(httpClient)
73-
if err != nil {
74-
return nil, err
75-
}
76-
client.parseCidrs(cidrs)
77-
}
65+
err = client.getCDNDataFromCache(httpClient)
7866
} else {
79-
for _, scraper := range defaultScrapers {
80-
cidrs, err := scraper(httpClient)
81-
if err != nil {
82-
return nil, err
83-
}
84-
client.parseCidrs(cidrs)
85-
}
67+
err = client.getCDNData(httpClient)
8668
}
69+
if err != nil {
70+
return nil, err
71+
}
72+
return client, nil
73+
}
74+
75+
func (c *Client) getCDNData(httpClient *http.Client) error {
76+
c.ranges = make(map[string][]string)
77+
c.rangers = make(map[string]cidranger.Ranger)
78+
79+
for provider, scraper := range defaultScrapers {
80+
cidrs, err := scraper(httpClient)
81+
if err != nil {
82+
return err
83+
}
8784

88-
if options.HasAuthInfo() {
89-
for _, scraper := range defaultScrapersWithOptions {
90-
cidrs, err := scraper(httpClient, options)
85+
c.ranges[provider] = cidrs
86+
ranger := cidranger.NewPCTrieRanger()
87+
for _, cidr := range cidrs {
88+
_, network, err := net.ParseCIDR(cidr)
9189
if err != nil {
92-
return nil, err
90+
continue
9391
}
94-
client.parseCidrs(cidrs)
92+
_ = ranger.Insert(cidranger.NewBasicRangerEntry(*network))
9593
}
9694
}
95+
if c.Options.HasAuthInfo() {
96+
for provider, scraper := range defaultScrapersWithOptions {
97+
cidrs, err := scraper(httpClient, c.Options)
98+
if err != nil {
99+
return err
100+
}
97101

98-
ranger := cidranger.NewPCTrieRanger()
99-
for cidr := range client.Data {
100-
_, network, err := net.ParseCIDR(cidr)
101-
if err != nil {
102-
continue
102+
c.ranges[provider] = cidrs
103+
ranger := cidranger.NewPCTrieRanger()
104+
for _, cidr := range cidrs {
105+
_, network, err := net.ParseCIDR(cidr)
106+
if err != nil {
107+
continue
108+
}
109+
_ = ranger.Insert(cidranger.NewBasicRangerEntry(*network))
110+
}
103111
}
104-
ranger.Insert(cidranger.NewBasicRangerEntry(*network))
105112
}
106-
client.ranger = ranger
107-
108-
return client, nil
113+
return nil
109114
}
110115

111-
// parseCidrs inserts the scraped cidrs to the internal structure
112-
func (c *Client) parseCidrs(cidrs []string) {
113-
if c.Data == nil {
114-
c.Data = make(map[string]struct{})
116+
func (c *Client) getCDNDataFromCache(httpClient *http.Client) error {
117+
var err error
118+
c.ranges, err = scrapeProjectDiscovery(httpClient)
119+
if err != nil {
120+
return err
115121
}
116-
for _, cidr := range cidrs {
117-
c.Data[cidr] = struct{}{}
122+
123+
c.rangers = make(map[string]cidranger.Ranger)
124+
for provider, ranges := range c.ranges {
125+
ranger := cidranger.NewPCTrieRanger()
126+
127+
for _, cidr := range ranges {
128+
_, network, err := net.ParseCIDR(cidr)
129+
if err != nil {
130+
continue
131+
}
132+
_ = ranger.Insert(cidranger.NewBasicRangerEntry(*network))
133+
}
134+
c.rangers[provider] = ranger
118135
}
136+
return nil
119137
}
120138

121139
// Check checks if an IP is contained in the blacklist
122-
func (c *Client) Check(ip net.IP) (bool, error) {
123-
return c.ranger.Contains(ip)
140+
func (c *Client) Check(ip net.IP) (bool, string, error) {
141+
for provider, ranger := range c.rangers {
142+
if contains, err := ranger.Contains(ip); contains {
143+
return true, provider, err
144+
}
145+
}
146+
return false, "", nil
147+
}
148+
149+
// Ranges returns the providers and ranges for the cdn client
150+
func (c *Client) Ranges() map[string][]string {
151+
return c.ranges
124152
}

cdncheck_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ func TestCDNCheck(t *testing.T) {
1111
client, err := New()
1212
require.Nil(t, err, "Could not create cdncheck client")
1313

14-
found, err := client.Check(net.ParseIP("173.245.48.12"))
14+
found, provider, err := client.Check(net.ParseIP("173.245.48.12"))
15+
require.Equal(t, "cloudflare", provider, "could not get correct provider")
1516
require.Nil(t, err, "Could not check ip in ranger")
1617
require.True(t, found, "Could not check cloudlfare ip blacklist")
1718

18-
found, err = client.Check(net.ParseIP("127.0.0.1"))
19+
found, _, err = client.Check(net.ParseIP("127.0.0.1"))
1920
require.Nil(t, err, "Could not check ip in ranger")
2021
require.False(t, found, "Localhost IP found in blacklist")
2122
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/projectdiscovery/cdncheck
33
go 1.14
44

55
require (
6-
github.com/davecgh/go-spew v1.1.1 // indirect
6+
github.com/json-iterator/go v1.1.12
77
github.com/kr/text v0.2.0 // indirect
88
github.com/stretchr/testify v1.7.0
99
github.com/yl2chen/cidranger v1.0.2

go.sum

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
2-
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
32
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
43
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
54
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
6+
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
7+
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
68
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
79
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
810
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
9-
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
1011
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
1112
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
1213
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
14+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
15+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
16+
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
17+
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
1318
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1419
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
15-
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
1620
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
1722
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
1823
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
1924
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2025
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
2126
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
22-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2327
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2428
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
2529
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
2630
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
27-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
2831
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2932
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
3033
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

ranges.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"net/http"
66
"regexp"
77
"strings"
8+
9+
jsoniter "github.com/json-iterator/go"
810
)
911

1012
var cidrRegex = regexp.MustCompile(`[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,3}`)
@@ -173,21 +175,18 @@ func scrapeLeaseweb(httpClient *http.Client, options *Options) ([]string, error)
173175
return cidrs, nil
174176
}
175177

176-
func scrapeProjectDiscovery(httpClient *http.Client) ([]string, error) {
177-
resp, err := httpClient.Get("https://cdn.projectdiscovery.io/cdn/cdn-ips")
178+
func scrapeProjectDiscovery(httpClient *http.Client) (map[string][]string, error) {
179+
resp, err := httpClient.Get("https://cdn.nuclei.sh")
178180
if err != nil {
179181
return nil, err
180182
}
181183
defer resp.Body.Close()
182184

183-
data, err := ioutil.ReadAll(resp.Body)
184-
if err != nil {
185+
var data map[string][]string
186+
if err := jsoniter.NewDecoder(resp.Body).Decode(&data); err != nil {
185187
return nil, err
186188
}
187-
body := string(data)
188-
189-
cidrs := cidrRegex.FindAllString(body, -1)
190-
return cidrs, nil
189+
return data, nil
191190
}
192191

193192
func makeReqWithAuth(method, URL, headerName, bearerValue string) (*http.Request, error) {

0 commit comments

Comments
 (0)