forked from AdguardTeam/dnsproxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelpers.go
157 lines (135 loc) · 4.05 KB
/
helpers.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
package proxy
import (
"net"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/miekg/dns"
)
const retryNoError = 60 // Retry time for NoError SOA
// CheckDisabledAAAARequest checks if AAAA requests should be disabled or not and sets NoError empty response to given DNSContext if needed
func CheckDisabledAAAARequest(ctx *DNSContext, ipv6Disabled bool) bool {
if ipv6Disabled && ctx.Req.Question[0].Qtype == dns.TypeAAAA {
log.Debug("IPv6 is disabled. Reply with NoError to %s AAAA request", ctx.Req.Question[0].Name)
ctx.Res = genEmptyNoError(ctx.Req)
return true
}
return false
}
// GenEmptyMessage generates empty message with given response code and retry time
func GenEmptyMessage(request *dns.Msg, rCode int, retry uint32) *dns.Msg {
resp := dns.Msg{}
resp.SetRcode(request, rCode)
resp.RecursionAvailable = true
resp.Ns = genSOA(request, retry)
return &resp
}
// genEmptyNoError returns response without answer and NoError RCode
func genEmptyNoError(request *dns.Msg) *dns.Msg {
return GenEmptyMessage(request, dns.RcodeSuccess, retryNoError)
}
// genSOA returns SOA for an authority section
func genSOA(request *dns.Msg, retry uint32) []dns.RR {
zone := ""
if len(request.Question) > 0 {
zone = request.Question[0].Name
}
soa := dns.SOA{
// values copied from verisign's nonexistent .com domain
// their exact values are not important in our use case because they are used for domain transfers between primary/secondary DNS servers
Refresh: 1800,
Retry: retry,
Expire: 604800,
Minttl: 86400,
// copied from AdGuard DNS
Ns: "fake-for-negative-caching.adguard.com.",
Serial: 100500,
// rest is request-specific
Hdr: dns.RR_Header{
Name: zone,
Rrtype: dns.TypeSOA,
Ttl: 10,
Class: dns.ClassINET,
},
}
soa.Mbox = "hostmaster."
if len(zone) > 0 && zone[0] != '.' {
soa.Mbox += zone
}
return []dns.RR{&soa}
}
// ecsFromMsg returns the subnet from EDNS Client Subnet option of m if any.
func ecsFromMsg(m *dns.Msg) (subnet *net.IPNet, scope int) {
opt := m.IsEdns0()
if opt == nil {
return nil, 0
}
var ip net.IP
var mask net.IPMask
for _, e := range opt.Option {
sn, ok := e.(*dns.EDNS0_SUBNET)
if !ok {
continue
}
switch sn.Family {
case 1:
ip = sn.Address.To4()
mask = net.CIDRMask(int(sn.SourceNetmask), netutil.IPv4BitLen)
case 2:
ip = sn.Address
mask = net.CIDRMask(int(sn.SourceNetmask), netutil.IPv6BitLen)
default:
continue
}
return &net.IPNet{IP: ip, Mask: mask}, int(sn.SourceScope)
}
return nil, 0
}
// setECS sets the EDNS client subnet option based on ip and scope into m. It
// returns masked IP and mask length.
func setECS(m *dns.Msg, ip net.IP, scope uint8) (subnet *net.IPNet) {
const (
// defaultECSv4 is the default length of network mask for IPv4 address
// in ECS option.
defaultECSv4 = 24
// defaultECSv6 is the default length of network mask for IPv6 address
// in ECS. The size of 7 octets is chosen as a reasonable minimum since
// at least Google's public DNS refuses requests containing the options
// with longer network masks.
defaultECSv6 = 56
)
e := &dns.EDNS0_SUBNET{
Code: dns.EDNS0SUBNET,
SourceScope: scope,
}
subnet = &net.IPNet{}
if ip4 := ip.To4(); ip4 != nil {
e.Family = 1
e.SourceNetmask = defaultECSv4
subnet.Mask = net.CIDRMask(defaultECSv4, netutil.IPv4BitLen)
ip = ip4
} else {
// Assume the IP address has already been validated.
e.Family = 2
e.SourceNetmask = defaultECSv6
subnet.Mask = net.CIDRMask(defaultECSv6, netutil.IPv6BitLen)
}
subnet.IP = ip.Mask(subnet.Mask)
e.Address = subnet.IP
// If OPT record already exists so just add EDNS option inside it. Note
// that servers may return FORMERR if they meet several OPT RRs.
if opt := m.IsEdns0(); opt != nil {
opt.Option = append(opt.Option, e)
return subnet
}
// Create an OPT record and add EDNS option inside it.
o := &dns.OPT{
Hdr: dns.RR_Header{
Name: ".",
Rrtype: dns.TypeOPT,
},
Option: []dns.EDNS0{e},
}
o.SetUDPSize(4096)
m.Extra = append(m.Extra, o)
return subnet
}