-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdns.go
135 lines (126 loc) · 2.54 KB
/
dns.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
// sean at shanghai
package main
import (
"log"
"net"
"sort"
"strings"
"time"
"github.com/miekg/dns"
)
// RequestArgs include domain and type
// we will query for every view
type RequestArgs struct {
Domain string
Type uint16
View string
ViewIP string
}
// NewRequest make a dns request struct with specified domain
// and client ip
func NewRequest(domain, clientIP string, tp uint16) *dns.Msg {
req := new(dns.Msg)
req.SetQuestion(domain, tp)
if clientIP != "" {
ip := net.ParseIP(clientIP)
if ip == nil {
log.Println("bad ip", clientIP)
return req
}
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
e := new(dns.EDNS0_SUBNET)
e.Code = dns.EDNS0SUBNET
e.Family = 1
e.SourceNetmask = 32
e.SourceScope = 0
e.Address = ip
opt.Option = append(opt.Option, e)
req.Extra = []dns.RR{opt}
}
return req
}
// MakeCall calls the request
func MakeCall(req *dns.Msg) (msg *dns.Msg, duration time.Duration, err error) {
c := new(dns.Client)
s := *flagServer + ":53"
count := 0
for {
if rateLimiter != nil {
rateLimiter.WaitForToken()
}
msg, duration, err = c.Exchange(req, s)
if err == nil {
return
}
ope, ok := err.(*net.OpError)
// time out error
if ok && ope.Timeout() {
count = count + 1
if count > 5 {
break
}
if *flagVerbose {
log.Println("retry for", req.Id)
}
} else {
return
}
}
return
}
// RetInfo stands for
// a result of dns request
type RetInfo struct {
Region string
Result string
Id uint16
}
// MakeRequest make a request on the fly
// write back result to channel
func MakeRequest(domain, clientIP, region string, tp uint16) (RetInfo, error) {
var r RetInfo
r.Region = region
req := NewRequest(domain, clientIP, tp)
r.Id = req.Id
msg, _, err := MakeCall(req)
if err != nil {
log.Println("make call error:", req)
return r, err
}
strs := make([]string, 0)
for _, a := range msg.Answer {
switch a.(type) {
case *dns.A:
r := a.(*dns.A)
strs = append(strs, r.A.String())
case *dns.CNAME:
c := a.(*dns.CNAME)
strs = append(strs, c.Target)
case *dns.AAAA:
aaaa := a.(*dns.AAAA)
strs = append(strs, aaaa.AAAA.String())
default:
strs = append(strs, a.String())
}
}
sort.Strings(strs)
str := strings.Join(strs, "\n")
r.Result = str
return r, nil
}
// IsSupportType return the type value if we support
func IsSupportType(str string) uint16 {
t := dns.TypeNone
str = strings.ToUpper(str)
switch str {
case "A":
t = dns.TypeA
case "AAAA":
t = dns.TypeAAAA
case "CNAME":
t = dns.TypeCNAME
}
return t
}