-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathcdnChecker.go
323 lines (287 loc) · 9.54 KB
/
cdnChecker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
package main
import (
"flag"
"fmt"
"io/ioutil"
"math"
"math/rand"
"os"
"sort"
"strings"
"sync"
"time"
"github.com/Workiva/go-datastructures/queue"
"github.com/miekg/dns"
"github.com/projectdiscovery/dnsx/libs/dnsx"
"github.com/projectdiscovery/retryabledns"
)
var validResolversList []string //可用dns服务器列表
var noCdnDomains []string //未使用cdn的域名列表
var useCdnDomains []string //使用cdn的域名列表
var noCdnIps []string //未使用cdn的ip列表
var domainsInfo []string //所有域名+对应ip信息记录在此列表中
var wg sync.WaitGroup
// 将文件内容转为字符列表,主要用于域名列表、cdn cname列表与dns服务器
func FileContentToList(filePath string) []string {
fileContent, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println("fail to open file: " + filePath)
os.Exit(2)
}
fileContentStr := strings.ReplaceAll(string(fileContent), "\r\n", "\n")
contentList := strings.Split(fileContentStr, "\n")
var newList []string
for _, element := range contentList {
if element != "" {
newList = append(newList, element)
}
}
return newList
}
// 判断字符串在数组元素中是否包含
func In(target string, str_array []string) bool {
sort.Strings(str_array)
index := sort.SearchStrings(str_array, target)
if index < len(str_array) && str_array[index] == target {
return true
}
return false
}
// 通过解析特定域名获取ip地址来找出提供列表中可用dns服务器
func FilterValidResolver(resolver string) {
defer wg.Done()
retries := 1
tempResolverList := []string{resolver}
dnsClient, _ := retryabledns.New(tempResolverList, retries)
dnsResponses, _ := dnsClient.Query("public1.114dns.com", dns.TypeA)
if In("114.114.114.114", dnsResponses.A) {
validResolversList = append(validResolversList, resolver)
}
}
// 判断域名的cname是否包含cdn cname,如果包含则判定使用了cdn
func InCdnCnameList(domainCnameList []string, cdnCnameList []string) bool {
inCdnCname := false
for _, domainCname := range domainCnameList {
for _, cdnCname := range cdnCnameList {
if strings.Contains(domainCname, cdnCname) {
inCdnCname = true
return inCdnCname
}
}
}
return inCdnCname
}
// 获取域名在特定dns上的解析ip,并且以.分割ip,取ip的前三部分,即解析ip为1.1.1.1,最终输出为[1.1.1],便于判断多个ip是否在相同网段
func ResolvDomainIpPart(domain string, resolver string) ([]string, error) {
var domainIpsPart []string
retries := 1
resolverList := []string{resolver}
dnsClient, err := retryabledns.New(resolverList, retries)
if err != nil {
return domainIpsPart, err
}
dnsResponses, err := dnsClient.Query(domain, dns.TypeA)
if err != nil {
return domainIpsPart, err
} else if In(resolver, dnsResponses.A) { //如果dns的ip出现在查询结果中,判为误报,忽略结果
return domainIpsPart, nil
}
ipsList := dnsResponses.A //[1.1.1.1, 2.2.2.2, 3.3.3.3]
if len(ipsList) > 0 {
for _, ip := range ipsList {
ipParts := strings.Split(ip, ".")
ipSplit := ipParts[0] + "." + ipParts[1] + "." + ipParts[2]
domainIpsPart = UniqueStrList(append(domainIpsPart, ipSplit))
}
}
return domainIpsPart, nil
}
// 字符型列表去重去空
func UniqueStrList(strList []string) []string {
uniqList := make([]string, 0)
tempMap := make(map[string]bool, len(strList))
for _, v := range strList {
if tempMap[v] == false && len(v) > 0 {
tempMap[v] = true
uniqList = append(uniqList, v)
}
}
return uniqList
}
// 生成count个[start,end)结束的不重复的随机数
func GenerateRandomNumber(start int, end int, count int) []int {
//范围检查
if end < start || (end-start) < count {
return nil
}
//存放结果的slice
nums := make([]int, 0)
//随机数生成器,加入时间戳保证每次生成的随机数不一样
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for len(nums) < count {
//生成随机数
num := r.Intn((end - start)) + start
//查重
exist := false
for _, v := range nums {
if v == num {
exist = true
break
}
}
if !exist {
nums = append(nums, num)
}
}
return nums
}
// 判断域名是否使用cdn
func CdnCheck(domain string, cdnCnameList []string, resolversList []string, dnsxClient *dnsx.DNSX) {
defer wg.Done()
isCdn, _, _ := dnsxClient.CdnCheck(domain) //通过dnsx自带方法识别cdn,主要为根据ip范围判断国外主流cdn厂商
dnsxResult, _ := dnsxClient.QueryOne(domain)
domainCnameList := dnsxResult.CNAME
tempDomainIpList := dnsxResult.A
var domainIpList []string
if len(tempDomainIpList) > 0 {
for _, tempIp := range tempDomainIpList {
if !In(tempIp, resolversList) {
domainIpList = append(domainIpList, tempIp)
}
}
} else {
return
}
if isCdn {
useCdnDomains = append(useCdnDomains, domain)
}
for _, domainIp := range domainIpList {
domainsInfo = UniqueStrList(append(domainsInfo, domain+":"+domainIp))
}
if len(domainCnameList) == 0 && len(domainIpList) > 0 { //无cname但有A记录,直接判定未使用cdn
noCdnDomains = append(noCdnDomains, domain)
noCdnIps = UniqueStrList(append(noCdnIps, domainIpList...))
} else if len(domainCnameList) > 0 && len(domainIpList) > 0 {
if InCdnCnameList(domainCnameList, cdnCnameList) { //cdn在cdn cname列表中包含,直接判定使用cdn
useCdnDomains = append(useCdnDomains, domain)
} else {
var domainIpPartList []string
randNums := GenerateRandomNumber(0, len(resolversList), 30)
for _, num := range randNums {
resolver := resolversList[num]
domainIpsWithResolver, err := ResolvDomainIpPart(domain, resolver)
if err != nil {
continue
}
domainIpPartList = UniqueStrList(append(domainIpPartList, domainIpsWithResolver...))
if len(domainIpPartList) > 3 { //不同段ip数量达到4个就跳出循环,避免每个dns服务器都解析增加耗时
break
}
}
//不同段ip数量达到4个就判定为使用了cdn
if len(domainIpPartList) > 3 {
useCdnDomains = append(useCdnDomains, domain)
} else {
noCdnDomains = append(noCdnDomains, domain)
noCdnIps = UniqueStrList(append(noCdnIps, domainIpList...))
}
}
}
}
func main() {
nowTime := time.Now().Format("200601021504")
df := flag.String("df", "", "domain list file")
cf := flag.String("cf", "cdn_cname", "cdn cname file")
r := flag.String("r", "", "dns resolvers file")
o := flag.String("o", "no_cdn_domains"+nowTime+".txt", "output domains that are not using cdn to file")
oi := flag.String("oi", "no_cdn_ips"+nowTime+".txt", "output ips that are not using cdn to file")
oc := flag.String("oc", "use_cdn_domains"+nowTime+".txt", "output domains that are using cdn to file")
od := flag.String("od", "domain_info"+nowTime+".txt", "output domain info(domain:ip) to file")
flag.Parse()
noCdnDomainsFileName := *o
noCdnIpsFileName := *oi
useCdnDomainsFileName := *oc
domainsInfoFileName := *od
//get domains list
domainsListFile := *df
var domainsList []string
domainsList = UniqueStrList(FileContentToList(domainsListFile))
//get cdn cname list
cdnCnameFile := *cf
var cdnCnameList []string
cdnCnameList = UniqueStrList(FileContentToList(cdnCnameFile))
//get resolvers list
resolversFile := *r
tempResolversList := UniqueStrList(FileContentToList(resolversFile))
queResolvers := queue.New(5) //dns服务器队列
for _, resolver := range tempResolversList {
queResolvers.Put(resolver)
}
for queResolvers.Len() > 0 {
wg.Add(1)
queResolverList, _ := queResolvers.Get(1)
queResolver := queResolverList[0].(string)
go FilterValidResolver(queResolver)
}
wg.Wait()
if len(validResolversList) < 20 {
fmt.Println("The number of valid resolvers is less than 20, May affect the accuracy of the results")
}
var DefaultOptions = dnsx.Options{
BaseResolvers: validResolversList,
MaxRetries: 5,
QuestionTypes: []uint16{dns.TypeA},
TraceMaxRecursion: math.MaxUint16,
Hostsfile: true,
}
//init dnsx client
dnsxClient, _ := dnsx.New(DefaultOptions)
que := queue.New(5) //域名队列
for _, domain := range domainsList {
que.Put(domain)
}
for que.Len() > 0 {
wg.Add(1)
queDomainList, _ := que.Get(1)
queDomain := queDomainList[0].(string)
go CdnCheck(queDomain, cdnCnameList, validResolversList, dnsxClient)
}
wg.Wait()
//未使用cdn域名写入文件
if len(noCdnDomains) > 0 {
noCdnDomains = UniqueStrList(noCdnDomains)
noCdnDomainsFile, _ := os.OpenFile(noCdnDomainsFileName, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
defer noCdnDomainsFile.Close()
for _, noCdnDomain := range noCdnDomains {
noCdnDomainsFile.WriteString(noCdnDomain + "\n")
}
}
//未使用cdn的ip写入文件
if len(noCdnIps) > 0 {
noCdnIps = UniqueStrList(noCdnIps)
noCdnIpsFile, _ := os.OpenFile(noCdnIpsFileName, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
defer noCdnIpsFile.Close()
for _, noCdnIp := range noCdnIps {
fmt.Println(noCdnIp)
noCdnIpsFile.WriteString(noCdnIp + "\n")
}
}
//使用cdn域名写入文件
if len(useCdnDomains) > 0 {
useCdnDomains = UniqueStrList(useCdnDomains)
useCdnDomainsFile, _ := os.OpenFile(useCdnDomainsFileName, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
defer useCdnDomainsFile.Close()
for _, useCdnDomain := range useCdnDomains {
useCdnDomainsFile.WriteString(useCdnDomain + "\n")
}
}
//域名+对应ip信息写入文件
if len(domainsInfo) > 0 {
domainsInfo = UniqueStrList(domainsInfo)
domainsInfoFile, _ := os.OpenFile(domainsInfoFileName, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
defer domainsInfoFile.Close()
for _, domainInfo := range domainsInfo {
domainsInfoFile.WriteString(domainInfo + "\n")
}
}
}