forked from shuque/getdns
/
main.go
119 lines (98 loc) · 2.4 KB
/
main.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
package getdns
import (
"fmt"
"github.com/miekg/dns"
"net"
"strings"
"time"
)
/*
* makeMessage() - construct DNS message structure
*/
func makeMessage(c *Context, qname, qtype, qclass string, ext Extension) *dns.Msg {
m := new(dns.Msg)
m.Id = dns.Id()
if c.restype == RESOLUTION_STUB {
m.RecursionDesired = true
} else {
m.RecursionDesired = false
}
if c.adflag {
m.AuthenticatedData = true
}
if c.cdflag {
m.CheckingDisabled = true
}
if ext["dnssec_return_status"] || ext["dnssec_return_only_secure"] || ext["dnssec_return_validation_chain"] {
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetDo()
m.Extra = append(m.Extra, opt)
}
m.Question = make([]dns.Question, 1)
qtype_int, ok := dns.StringToType[strings.ToUpper(qtype)]
if !ok {
fmt.Printf("%s: Unrecognized query type.\n", qtype)
return nil
}
qclass_int, ok := dns.StringToClass[strings.ToUpper(qclass)]
if !ok {
fmt.Printf("%s: Unrecognized query class.\n", qclass)
return nil
}
m.Question[0] = dns.Question{qname, qtype_int, qclass_int}
return m
}
/*
* doQuery() - perform DNS query with timeouts and retries as needed
*/
func doQuery(ctx *Context, qname, qtype, qclass string, ext Extension) (r *Reply, err error) {
var retries = ctx.retries
var timeout = ctx.timeout
qname = dns.Fqdn(qname)
r = new(Reply)
r.Qname = qname
r.Qtype = qtype
r.Qclass = qclass
m := makeMessage(ctx, qname, qtype, qclass, ext)
if ctx.tcp {
r.Transport = "tcp"
r.Msg, r.Rtt, r.Err = sendRequest(ctx, m, "tcp", timeout)
return r, r.Err
}
r.Transport = "udp"
for retries > 0 {
r.Msg, r.Rtt, r.Err = sendRequest(ctx, m, "udp", timeout)
if r.Err == nil {
break
}
if r.Err == dns.ErrId {
retries--
continue
}
if nerr, ok := r.Err.(net.Error); ok && !nerr.Timeout() {
break
}
retries--
timeout = timeout * 2
}
if r.Err == dns.ErrTruncated {
fmt.Println("Truncated; Retrying over TCP ..")
r.Truncated = true
r.Retried = true
r.Transport = "tcp"
r.Msg, r.Rtt, r.Err = sendRequest(ctx, m, "tcp", timeout)
}
return r, r.Err
}
/*
* sendRequest() - send a DNS query
*/
func sendRequest(ctx *Context, m *dns.Msg, transport string, timeout time.Duration) (response *dns.Msg, rtt time.Duration, err error) {
c := new(dns.Client)
c.Timeout = timeout
c.Net = transport // "udp" or "tcp"
response, rtt, err = c.Exchange(m, addressString(ctx.server, ctx.port))
return
}