1
1
package dns
2
2
3
3
import (
4
+ "context"
4
5
"encoding/json"
5
- "errors"
6
6
"fmt"
7
7
"net"
8
8
"net/http"
9
9
"strings"
10
10
"sync"
11
11
12
- "github.com/areYouLazy/libhosty"
13
12
"github.com/containers/gvisor-tap-vsock/pkg/types"
14
13
"github.com/miekg/dns"
15
14
log "github.com/sirupsen/logrus"
@@ -18,34 +17,13 @@ import (
18
17
type dnsHandler struct {
19
18
zones []types.Zone
20
19
zonesLock sync.RWMutex
21
- udpClient * dns.Client
22
- tcpClient * dns.Client
23
- hostsFile * HostsFile
24
- dnsConfig * dnsConfig
25
20
}
26
21
27
- func newDNSHandler (zones []types.Zone ) (* dnsHandler , error ) {
28
- dnsConfig , err := newDNSConfig ()
29
- if err != nil {
30
- return nil , err
31
- }
32
-
33
- hostsFile , err := NewHostsFile ("" )
34
- if err != nil {
35
- return nil , err
36
- }
37
-
38
- return & dnsHandler {
39
- zones : zones ,
40
- tcpClient : & dns.Client {Net : "tcp" },
41
- udpClient : & dns.Client {Net : "udp" },
42
- dnsConfig : dnsConfig ,
43
- hostsFile : hostsFile ,
44
- }, nil
45
- }
46
-
47
- func (h * dnsHandler ) handle (w dns.ResponseWriter , dnsClient * dns.Client , r * dns.Msg , responseMessageSize int ) {
48
- m := h .addAnswers (dnsClient , r )
22
+ func (h * dnsHandler ) handle (w dns.ResponseWriter , r * dns.Msg , responseMessageSize int ) {
23
+ m := new (dns.Msg )
24
+ m .SetReply (r )
25
+ m .RecursionAvailable = true
26
+ h .addAnswers (m )
49
27
edns0 := r .IsEdns0 ()
50
28
if edns0 != nil {
51
29
responseMessageSize = int (edns0 .UDPSize ())
@@ -57,25 +35,23 @@ func (h *dnsHandler) handle(w dns.ResponseWriter, dnsClient *dns.Client, r *dns.
57
35
}
58
36
59
37
func (h * dnsHandler ) handleTCP (w dns.ResponseWriter , r * dns.Msg ) {
60
- h .handle (w , h . tcpClient , r , dns .MaxMsgSize )
38
+ h .handle (w , r , dns .MaxMsgSize )
61
39
}
62
40
63
41
func (h * dnsHandler ) handleUDP (w dns.ResponseWriter , r * dns.Msg ) {
64
- h .handle (w , h . udpClient , r , dns .MinMsgSize )
42
+ h .handle (w , r , dns .MinMsgSize )
65
43
}
66
44
67
45
func (h * dnsHandler ) addLocalAnswers (m * dns.Msg , q dns.Question ) bool {
68
- // resolve only ipv4 requests
69
- if q .Qtype != dns .TypeA {
70
- return false
71
- }
72
-
73
46
h .zonesLock .RLock ()
74
47
defer h .zonesLock .RUnlock ()
75
48
76
49
for _ , zone := range h .zones {
77
50
zoneSuffix := fmt .Sprintf (".%s" , zone .Name )
78
51
if strings .HasSuffix (q .Name , zoneSuffix ) {
52
+ if q .Qtype != dns .TypeA {
53
+ return false
54
+ }
79
55
for _ , record := range zone .Records {
80
56
withoutZone := strings .TrimSuffix (q .Name , zoneSuffix )
81
57
if (record .Name != "" && record .Name == withoutZone ) ||
@@ -107,55 +83,127 @@ func (h *dnsHandler) addLocalAnswers(m *dns.Msg, q dns.Question) bool {
107
83
m .Rcode = dns .RcodeNameError
108
84
return true
109
85
}
110
- ip , err := h .hostsFile .LookupByHostname (q .Name )
111
- if err != nil {
112
- // ignore only ErrHostnameNotFound error
113
- if ! errors .Is (err , libhosty .ErrHostnameNotFound ) {
114
- log .Errorf ("Error during looking in hosts file records: %v" , err )
115
- }
116
- } else {
117
- m .Answer = append (m .Answer , & dns.A {
118
- Hdr : dns.RR_Header {
119
- Name : q .Name ,
120
- Rrtype : dns .TypeA ,
121
- Class : dns .ClassINET ,
122
- Ttl : 0 ,
123
- },
124
- A : ip ,
125
- })
126
- return true
127
- }
128
86
}
129
87
return false
130
88
}
131
89
132
- func (h * dnsHandler ) addAnswers (dnsClient * dns.Client , r * dns.Msg ) * dns.Msg {
133
- m := new (dns.Msg )
134
- m .SetReply (r )
135
- m .RecursionAvailable = true
136
-
90
+ func (h * dnsHandler ) addAnswers (m * dns.Msg ) {
137
91
for _ , q := range m .Question {
138
92
if done := h .addLocalAnswers (m , q ); done {
139
- return m
93
+ return
94
+ }
140
95
141
- // ignore IPv6 request, we support only IPv4 requests for now
142
- } else if q .Qtype == dns .TypeAAAA {
143
- return m
96
+ resolver := net.Resolver {
97
+ PreferGo : false ,
144
98
}
145
- }
146
- for _ , nameserver := range h .dnsConfig .Nameservers () {
147
- msg := r .Copy ()
148
- r , _ , err := dnsClient .Exchange (msg , nameserver )
149
- // return first good answer
150
- if err == nil {
151
- return r
99
+ switch q .Qtype {
100
+ case dns .TypeA :
101
+ ips , err := resolver .LookupIPAddr (context .TODO (), q .Name )
102
+ if err != nil {
103
+ m .Rcode = dns .RcodeNameError
104
+ return
105
+ }
106
+ for _ , ip := range ips {
107
+ if len (ip .IP .To4 ()) != net .IPv4len {
108
+ continue
109
+ }
110
+ m .Answer = append (m .Answer , & dns.A {
111
+ Hdr : dns.RR_Header {
112
+ Name : q .Name ,
113
+ Rrtype : dns .TypeA ,
114
+ Class : dns .ClassINET ,
115
+ Ttl : 0 ,
116
+ },
117
+ A : ip .IP .To4 (),
118
+ })
119
+ }
120
+ case dns .TypeCNAME :
121
+ cname , err := resolver .LookupCNAME (context .TODO (), q .Name )
122
+ if err != nil {
123
+ m .Rcode = dns .RcodeNameError
124
+ return
125
+ }
126
+ m .Answer = append (m .Answer , & dns.CNAME {
127
+ Hdr : dns.RR_Header {
128
+ Name : q .Name ,
129
+ Rrtype : dns .TypeCNAME ,
130
+ Class : dns .ClassINET ,
131
+ Ttl : 0 ,
132
+ },
133
+ Target : cname ,
134
+ })
135
+ case dns .TypeMX :
136
+ records , err := resolver .LookupMX (context .TODO (), q .Name )
137
+ if err != nil {
138
+ m .Rcode = dns .RcodeNameError
139
+ return
140
+ }
141
+ for _ , mx := range records {
142
+ m .Answer = append (m .Answer , & dns.MX {
143
+ Hdr : dns.RR_Header {
144
+ Name : q .Name ,
145
+ Rrtype : dns .TypeMX ,
146
+ Class : dns .ClassINET ,
147
+ Ttl : 0 ,
148
+ },
149
+ Mx : mx .Host ,
150
+ Preference : mx .Pref ,
151
+ })
152
+ }
153
+ case dns .TypeNS :
154
+ records , err := resolver .LookupNS (context .TODO (), q .Name )
155
+ if err != nil {
156
+ m .Rcode = dns .RcodeNameError
157
+ return
158
+ }
159
+ for _ , ns := range records {
160
+ m .Answer = append (m .Answer , & dns.NS {
161
+ Hdr : dns.RR_Header {
162
+ Name : q .Name ,
163
+ Rrtype : dns .TypeNS ,
164
+ Class : dns .ClassINET ,
165
+ Ttl : 0 ,
166
+ },
167
+ Ns : ns .Host ,
168
+ })
169
+ }
170
+ case dns .TypeSRV :
171
+ _ , records , err := resolver .LookupSRV (context .TODO (), "" , "" , q .Name )
172
+ if err != nil {
173
+ m .Rcode = dns .RcodeNameError
174
+ return
175
+ }
176
+ for _ , srv := range records {
177
+ m .Answer = append (m .Answer , & dns.SRV {
178
+ Hdr : dns.RR_Header {
179
+ Name : q .Name ,
180
+ Rrtype : dns .TypeSRV ,
181
+ Class : dns .ClassINET ,
182
+ Ttl : 0 ,
183
+ },
184
+ Port : srv .Port ,
185
+ Priority : srv .Priority ,
186
+ Target : srv .Target ,
187
+ Weight : srv .Weight ,
188
+ })
189
+ }
190
+ case dns .TypeTXT :
191
+ records , err := resolver .LookupTXT (context .TODO (), q .Name )
192
+ if err != nil {
193
+ m .Rcode = dns .RcodeNameError
194
+ return
195
+ }
196
+ m .Answer = append (m .Answer , & dns.TXT {
197
+ Hdr : dns.RR_Header {
198
+ Name : q .Name ,
199
+ Rrtype : dns .TypeTXT ,
200
+ Class : dns .ClassINET ,
201
+ Ttl : 0 ,
202
+ },
203
+ Txt : records ,
204
+ })
152
205
}
153
- log .Debugf ("Error during DNS Exchange: %s" , err )
154
206
}
155
-
156
- // return the error if none of configured nameservers has right answer
157
- m .Rcode = dns .RcodeNameError
158
- return m
159
207
}
160
208
161
209
type Server struct {
@@ -165,10 +213,7 @@ type Server struct {
165
213
}
166
214
167
215
func New (udpConn net.PacketConn , tcpLn net.Listener , zones []types.Zone ) (* Server , error ) {
168
- handler , err := newDNSHandler (zones )
169
- if err != nil {
170
- return nil , err
171
- }
216
+ handler := & dnsHandler {zones : zones }
172
217
return & Server {udpConn : udpConn , tcpLn : tcpLn , handler : handler }, nil
173
218
}
174
219
0 commit comments