4
4
"net"
5
5
"strings"
6
6
"sync"
7
+
8
+ "github.com/projectdiscovery/retryabledns"
7
9
)
8
10
9
11
var (
@@ -12,23 +14,50 @@ var (
12
14
DefaultCloudProviders string
13
15
)
14
16
17
+ // DefaultResolvers trusted (taken from fastdialer)
18
+ var DefaultResolvers = []string {
19
+ "1.1.1.1:53" ,
20
+ "1.0.0.1:53" ,
21
+ "8.8.8.8:53" ,
22
+ "8.8.4.4:53" ,
23
+ }
24
+
15
25
// Client checks for CDN based IPs which should be excluded
16
26
// during scans since they belong to third party firewalls.
17
27
type Client struct {
18
28
sync.Once
19
- cdn * providerScraper
20
- waf * providerScraper
21
- cloud * providerScraper
29
+ cdn * providerScraper
30
+ waf * providerScraper
31
+ cloud * providerScraper
32
+ retriabledns * retryabledns.Client
22
33
}
23
34
24
- // New creates a new firewall IP checking client.
35
+ // New creates cdncheck client with default options
36
+ // NewWithOpts should be preferred over this function
25
37
func New () * Client {
38
+ client , _ := NewWithOpts (3 , []string {})
39
+ return client
40
+ }
41
+
42
+ // NewWithOpts creates cdncheck client with custom options
43
+ func NewWithOpts (MaxRetries int , resolvers []string ) (* Client , error ) {
44
+ if MaxRetries <= 0 {
45
+ MaxRetries = 3
46
+ }
47
+ if len (resolvers ) == 0 {
48
+ resolvers = DefaultResolvers
49
+ }
50
+ retryabledns , err := retryabledns .New (resolvers , MaxRetries )
51
+ if err != nil {
52
+ return nil , err
53
+ }
26
54
client := & Client {
27
- cdn : newProviderScraper (generatedData .CDN ),
28
- waf : newProviderScraper (generatedData .WAF ),
29
- cloud : newProviderScraper (generatedData .Cloud ),
55
+ cdn : newProviderScraper (generatedData .CDN ),
56
+ waf : newProviderScraper (generatedData .WAF ),
57
+ cloud : newProviderScraper (generatedData .Cloud ),
58
+ retriabledns : retryabledns ,
30
59
}
31
- return client
60
+ return client , nil
32
61
}
33
62
34
63
// CheckCDN checks if an IP is contained in the cdn denylist
@@ -49,9 +78,7 @@ func (c *Client) CheckCloud(ip net.IP) (matched bool, value string, err error) {
49
78
return matched , value , err
50
79
}
51
80
52
- // Check checks if an IP is contained in the denylist
53
- //
54
- // It includes CDN, WAF and Cloud. Basically all varaint of individual functions
81
+ // Check checks if ip belongs to one of CDN, WAF and Cloud . It is generic method for Checkxxx methods
55
82
func (c * Client ) Check (ip net.IP ) (matched bool , value string , itemType string , err error ) {
56
83
if matched , value , err = c .cdn .Match (ip ); err == nil && matched && value != "" {
57
84
return matched , value , "cdn" , nil
@@ -65,6 +92,58 @@ func (c *Client) Check(ip net.IP) (matched bool, value string, itemType string,
65
92
return false , "" , "" , err
66
93
}
67
94
95
+ // Check Domain with fallback checks if domain belongs to one of CDN, WAF and Cloud . It is generic method for Checkxxx methods
96
+ // Since input is domain, as a fallback it queries CNAME records and checks if domain is WAF
97
+ func (c * Client ) CheckDomainWithFallback (domain string ) (matched bool , value string , itemType string , err error ) {
98
+ dnsData , err := c .retriabledns .Resolve (domain )
99
+ if err != nil {
100
+ return false , "" , "" , err
101
+ }
102
+ matched , value , itemType , err = c .CheckDNSResponse (dnsData )
103
+ if err != nil {
104
+ return false , "" , "" , err
105
+ }
106
+ if matched {
107
+ return matched , value , itemType , nil
108
+ }
109
+ // resolve cname
110
+ dnsData , err = c .retriabledns .CNAME (domain )
111
+ if err != nil {
112
+ return false , "" , "" , err
113
+ }
114
+ return c .CheckDNSResponse (dnsData )
115
+ }
116
+
117
+ // CheckDNSResponse is same as CheckDomainWithFallback but takes DNS response as input
118
+ func (c * Client ) CheckDNSResponse (dnsResponse * retryabledns.DNSData ) (matched bool , value string , itemType string , err error ) {
119
+ if dnsResponse .A != nil {
120
+ for _ , ip := range dnsResponse .A {
121
+ ipAddr := net .ParseIP (ip )
122
+ if ipAddr == nil {
123
+ continue
124
+ }
125
+ matched , value , itemType , err := c .Check (ipAddr )
126
+ if err != nil {
127
+ return false , "" , "" , err
128
+ }
129
+ if matched {
130
+ return matched , value , itemType , nil
131
+ }
132
+ }
133
+ }
134
+ if dnsResponse .CNAME != nil {
135
+ matched , discovered , itemType , err := c .CheckSuffix (dnsResponse .CNAME ... )
136
+ if err != nil {
137
+ return false , "" , itemType , err
138
+ }
139
+ if matched {
140
+ // for now checkSuffix only checks for wafs
141
+ return matched , discovered , itemType , nil
142
+ }
143
+ }
144
+ return false , "" , "" , err
145
+ }
146
+
68
147
func mapKeys (m map [string ][]string ) string {
69
148
keys := make ([]string , 0 , len (m ))
70
149
for k := range m {
0 commit comments