djbdnscurve6 53
djbdnscurve6
Loading...
Searching...
No Matches
dns_transmit.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <unistd.h>
4#include "socket_if.h"
5#include "alloc.h"
6#include "error.h"
7#include "byte.h"
8#include "uint_t.h"
9#include "ip.h"
10#include "dns.h"
11#include "curvedns.h"
12
13#define MAXUDPLOOP 5 // smaller values possible here; larger not
14
16extern unsigned int fallback;
17
18int getscopeid(const struct dns_transmit *d,const char *ip)
19{
20 int i;
21
22 if (byte_diff(ip,2,V6linklocal)) return 0;
23 for (i = 0; i < QUERY_MAXNS; ++i)
24 if (byte_equal(d->servers + 16 * i,16,ip))
25 return scope_ids[i];
26 return 0;
27}
28
29int serverwantstcp(const char *buf,unsigned int len)
30{
31 char out[12];
32
33 if (!dns_packet_copy(buf,len,0,out,12)) return 1;
34 if (out[2] & 2) return 1;
35 return 0;
36}
37
38int serverfailed(const char *buf,unsigned int len,char *server) /* Joseph Tam's fix */
39{
40 char out[12];
41 unsigned int rcode;
42
43 if (!dns_packet_copy(buf,len,0,out,12)) return 1;
44 rcode = out[3] & 15;
45 if ((rcode == 0) || (rcode == 3)) return 0;
46 if (rcode == 5) byte_zero(server,16);
47 errno = EAGAIN;
48 return 1;
49}
50
51int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
52{
53 char out[12];
54 char *dn;
55 unsigned int pos;
56
57 pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
58 if (byte_diff(out,2,d->nonce + 8)) return 1;
59 if (out[4] != 0) return 1;
60 if (out[5] != 1) return 1;
61
62 dn = 0;
63 pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
64 if (!dns_domain_equal(dn,d->name)) { alloc_free(dn); return 1; }
65 alloc_free(dn);
66
67 pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
68 if (byte_diff(out,2,d->qtype)) return 1;
69 if (byte_diff(out + 2,2,DNS_C_IN)) return 1;
70
71 return 0;
72}
73
74void packetfree(struct dns_transmit *d)
75{
76 if (!d->packet) return;
77 alloc_free(d->packet);
78 d->packet = 0;
79}
80
81void queryfree(struct dns_transmit *d)
82{
83 if (!d->query) return;
84 alloc_free(d->query);
85 d->query = 0;
86}
87
88void socketfree(struct dns_transmit *d)
89{
90 if (!d->s1) return;
91 close(d->s1 - 1);
92 d->s1 = 0;
93}
94
96{
97 queryfree(d);
100}
101
103{
104 int j;
105
106 for (j = 0; j < 10; ++j) {
107 if (socket_bind(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
108 return 0;
109 }
110
111 if (socket_bind(d->s1 - 1,d->localip,0,d->scope_id) == 0)
112 return 0;
113
114 return DNS_COM;
115}
116
118{
119 int j;
120
121 for (j = 0; j < 10; ++j) {
122 if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
123 return 0;
124 }
125
126 if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
127 return 0;
128
129 return DNS_COM;
130}
131
133{
134 int j;
135
136 for (j = 0; j < 10; ++j) {
137 if (socket_bind4(d->s1 - 1,d->localip + 12,1025 + dns_random(64510)) == 0)
138 return 0;
139 }
140
141 if (socket_bind4(d->s1 - 1,d->localip + 12,0) == 0)
142 return 0;
143
144 return DNS_COM;
145}
146
147static const int timeouts[5] = { 1, 2, 4, 8, 16 }; /* five query trials; quadratic schedule */
148
149int thisudp(struct dns_transmit *d)
150{
151 const char *ip;
152
153 socketfree(d);
154
155 while (d->udploop < MAXUDPLOOP) {
156 for (; d->curserver < QUERY_MAXNS; ++d->curserver) {
157 ip = d->servers + 16 * d->curserver;
158 if (byte_equal(ip,16,V6localnet)) continue; /* skip undefined NS */
159
160 if (fallback && d->udploop > fallback) d->keys = 0;
161 cns_query(d);
162
163 if (ip6_isv4mapped(ip)) {
164 d->s1 = 1 + socket_udp4();
165 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
166 if (randombind4(d) < 0) { dns_transmit_free(d); return DNS_COM; }
167 } else {
168 d->s1 = 1 + socket_udp6();
169 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
170 if (randombind6(d) < 0) { dns_transmit_free(d); return DNS_COM; }
171 }
172
173 if (byte_equal(ip,2,V6linklocal) && !d->scope_id)
174 d->scope_id = getscopeid(d,ip);
175 if (socket_connect(d->s1 - 1,ip,DNSPORT,d->scope_id) == 0)
176 if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
177 struct taia now;
178 taia_now(&now);
179 taia_uint(&d->deadline,timeouts[d->udploop]);
180 taia_add(&d->deadline,&d->deadline,&now);
181 d->tcpstate = 0;
182 return 0;
183 }
184 socketfree(d);
185 }
186 ++d->udploop;
187 d->curserver = 0;
188 }
189
190 dns_transmit_free(d); return DNS_COM;
191}
192
193int firstudp(struct dns_transmit *d)
194{
195 d->curserver = 0;
196
197 return thisudp(d);
198}
199
200int nextudp(struct dns_transmit *d)
201{
202 ++d->curserver;
203 return thisudp(d);
204}
205
206int thistcp(struct dns_transmit *d)
207{
208 struct taia now;
209 const char *ip;
210
211 socketfree(d);
212 packetfree(d);
213
214 for (; d->curserver < QUERY_MAXNS; ++d->curserver) {
215 ip = d->servers + 16 * d->curserver;
216 if (byte_equal(ip,16,V6localnet)) continue; /* skip undefined NS */
217 cns_query(d);
218
219 if (ip6_isv4mapped(ip)) {
220 d->s1 = 1 + socket_tcp4();
221 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
222 if (randombind4(d) < 0) { dns_transmit_free(d); return DNS_COM; }
223 } else {
224 d->s1 = 1 + socket_tcp6();
225 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
226 if (randombind6(d) < 0) { dns_transmit_free(d); return DNS_COM; }
227 }
228
229 taia_now(&now);
230 taia_uint(&d->deadline,10);
231 taia_add(&d->deadline,&d->deadline,&now);
232
233 if (byte_equal(ip,2,V6linklocal) && !d->scope_id)
234 d->scope_id = getscopeid(d,ip);
235 if (socket_connect(d->s1 - 1,ip,DNSPORT,d->scope_id) == 0) {
236 d->tcpstate = 2;
237 return 0;
238 }
239 if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
240 d->tcpstate = 1;
241 return 0;
242 }
243
244 socketfree(d);
245 }
246
247 dns_transmit_free(d); return DNS_COM;
248}
249
250int firsttcp(struct dns_transmit *d)
251{
252 d->curserver = 0;
253 if (d->flagedns) {
254 d->query[13] = '\0'; // wipe Add RR (offset +2)
255 d->querylen -= 11; // length w/o EDNS
256 d->flagedns = 0; // reset for this q
257 }
258 return thistcp(d);
259}
260
261int nexttcp(struct dns_transmit *d)
262{
263 ++d->curserver;
264 return thistcp(d);
265}
266
267/* Legacy calls */
268
270 char qflags[2],const char *q,const char qtype[2],const char localip[16])
271{
272
273 return cns_transmit_start(d,servers,qflags,q,qtype,localip,0,0,0);
274}
275
277 char qflags[2],const char *q,const char qtype[2], \
278 const char localip[16],const uint32 scopes[QUERY_MAXNS])
279{
280 byte_copy((char *)scope_ids,128,(char *)scopes);
281
282 return cns_transmit_start(d,servers,qflags,q,qtype,localip,0,0,0);
283}
284
285void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
286{
287 x->fd = d->s1 - 1;
288
289 switch (d->tcpstate) {
290 case 0: case 3: case 4: case 5:
291 x->events = IOPAUSE_READ;
292 break;
293 case 1: case 2:
294 x->events = IOPAUSE_WRITE;
295 break;
296 }
297
298 if (taia_less(&d->deadline,deadline))
299 *deadline = d->deadline;
300}
301
302int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
303{
304 unsigned char ch;
305 int r;
306 int fd;
307 unsigned int len = udp_msgsize();
308 char udpbuf[len + 1];
309
310 errno = EIO;
311 fd = d->s1 - 1;
312
313 if (!x->revents) {
314 if (taia_less((struct taia *)when,&d->deadline)) return 0;
315 errno = ETIMEDOUT;
316 if (d->tcpstate == 0) return nextudp(d);
317 return nexttcp(d);
318 }
319
320/*
321have attempted to send UDP query to each server udploop times
322have sent query to curserver on UDP socket s
323*/
324 if (d->tcpstate == 0) {
325 r = recv(fd,udpbuf,sizeof(udpbuf),0);
326 if (r <= 0) {
327 if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
328 return nextudp(d);
329 }
330 if (r + 1 > sizeof(udpbuf)) return 0;
331 len = r;
332
333 if (cns_uncurve(d,udpbuf,&len)) return nextudp(d); // skipping wrong answering CurveDNS NS
334 if (irrelevant(d,udpbuf,len)) return nextudp(d);
335 if (serverwantstcp(udpbuf,len)) return firsttcp(d);
336 if (serverfailed(udpbuf,r,(char *)(d->servers + 16 * d->curserver))) {
337 if (d->udploop == 2) return 0;
338 return nextudp(d);
339 }
340 socketfree(d);
341
342 d->packetlen = len;
343 d->packet = alloc(d->packetlen);
344 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
345 byte_copy(d->packet,d->packetlen,udpbuf);
346 queryfree(d);
347 return 1;
348 }
349
350/*
351have sent connection attempt to curserver on TCP socket s
352pos not defined
353*/
354 if (d->tcpstate == 1) {
355 if (!socket_connected(fd)) return nexttcp(d);
356 d->pos = 0;
357 d->flagedns = 0;
358 d->tcpstate = 2;
359 return 0;
360 }
361
362/*
363have connection to curserver on TCP socket s
364have sent pos bytes of query
365*/
366 if (d->tcpstate == 2) {
367 r = write(fd,d->query + d->pos,d->querylen - d->pos);
368 if (r <= 0) return nexttcp(d);
369 d->pos += r;
370 if (d->pos == d->querylen) {
371 struct taia now;
372 taia_now(&now);
373 taia_uint(&d->deadline,10);
374 taia_add(&d->deadline,&d->deadline,&now);
375 d->tcpstate = 3;
376 }
377 return 0;
378 }
379
380/*
381have sent entire query to curserver on TCP socket s
382pos not defined
383*/
384 if (d->tcpstate == 3) {
385 r = read(fd,&ch,1);
386 if (r <= 0) return nexttcp(d);
387 d->packetlen = ch;
388 d->tcpstate = 4;
389 return 0;
390 }
391
392/*
393have sent entire query to curserver on TCP socket s
394pos not defined
395have received one byte of packet length into packetlen
396*/
397 if (d->tcpstate == 4) {
398 r = read(fd,&ch,1);
399 if (r <= 0) return nexttcp(d);
400 d->packetlen <<= 8;
401 d->packetlen += ch;
402 d->tcpstate = 5;
403 d->pos = 0;
404 d->packet = alloc(d->packetlen);
405 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
406 return 0;
407 }
408
409/*
410have sent entire query to curserver on TCP socket s
411have received entire packet length into packetlen
412packet is allocated
413have received pos bytes of packet
414*/
415 if (d->tcpstate == 5) {
416 r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
417 if (r <= 0) return nexttcp(d);
418 d->pos += r;
419 if (d->pos < d->packetlen) return 0;
420
421 socketfree(d);
422 if (cns_uncurve(d,d->packet,&d->packetlen)) return nexttcp(d);
423 if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
424 if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
425 if (serverfailed(d->packet,d->packetlen,(char *)(d->servers + 16 * d->curserver)))
426 return nexttcp(d);
427
428 queryfree(d);
429 return 1;
430 }
431
432 return 0;
433}
int fd
Definition: axfr-get.c:103
struct tai now
Definition: axfrdns.c:132
char ip[16]
Definition: axfrdns.c:128
uint16 len
Definition: axfrdns.c:322
char buf[MSGSIZE]
Definition: axfrdns.c:321
int cns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], char qflags[2], const char *q, const char qtype[2], const char localip[16], const char keys[QUERY_MAXNS *KEY_LEN], const char pubkey[KEY_LEN], const char *suffix)
Definition: curvedns.c:286
void cns_query(struct dns_transmit *d)
Definition: curvedns.c:82
unsigned int udp_msgsize(void)
Definition: curvedns.c:38
int cns_uncurve(const struct dns_transmit *d, char *buf, unsigned int *lenp)
Definition: curvedns.c:134
#define DNSPORT
Definition: curvedns.h:10
#define QUERY_MAXIPLEN
Definition: dns.h:55
#define DNS_C_IN
Definition: dns.h:62
#define QUERY_MAXNS
Definition: dns.h:54
#define DNS_COM
Definition: dns.h:42
int dns_domain_equal(const char *dn1, const char *dn2)
Definition: dns_domain.c:39
unsigned int dns_packet_getname(const char *buf, unsigned int len, unsigned int pos, char **d)
Definition: dns_packet.c:35
unsigned int dns_packet_copy(const char *buf, unsigned int len, unsigned int pos, char *out, unsigned int outlen)
Definition: dns_packet.c:8
unsigned int dns_random(unsigned int n)
Definition: dns_random.c:55
void dns_transmit_io(struct dns_transmit *d, iopause_fd *x, struct taia *deadline)
Definition: dns_transmit.c:285
int thisudp(struct dns_transmit *d)
Definition: dns_transmit.c:149
void socketfree(struct dns_transmit *d)
Definition: dns_transmit.c:88
void packetfree(struct dns_transmit *d)
Definition: dns_transmit.c:74
int dns_transmit_start6(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], char qflags[2], const char *q, const char qtype[2], const char localip[16], const uint32 scopes[QUERY_MAXNS])
Definition: dns_transmit.c:276
void dns_transmit_free(struct dns_transmit *d)
Definition: dns_transmit.c:95
int randombind6(struct dns_transmit *d)
Definition: dns_transmit.c:117
int getscopeid(const struct dns_transmit *d, const char *ip)
Definition: dns_transmit.c:18
int randombind4(struct dns_transmit *d)
Definition: dns_transmit.c:132
int thistcp(struct dns_transmit *d)
Definition: dns_transmit.c:206
int firstudp(struct dns_transmit *d)
Definition: dns_transmit.c:193
int nexttcp(struct dns_transmit *d)
Definition: dns_transmit.c:261
int serverwantstcp(const char *buf, unsigned int len)
Definition: dns_transmit.c:29
#define MAXUDPLOOP
Definition: dns_transmit.c:13
uint32 scope_ids[QUERY_MAXNS]
Definition: dns_transmit.c:15
int serverfailed(const char *buf, unsigned int len, char *server)
Definition: dns_transmit.c:38
void queryfree(struct dns_transmit *d)
Definition: dns_transmit.c:81
int randombind(struct dns_transmit *d)
Definition: dns_transmit.c:102
unsigned int fallback
Definition: curvedns.c:21
int dns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], char qflags[2], const char *q, const char qtype[2], const char localip[16])
Definition: dns_transmit.c:269
int dns_transmit_get(struct dns_transmit *d, const iopause_fd *x, const struct taia *when)
Definition: dns_transmit.c:302
int nextudp(struct dns_transmit *d)
Definition: dns_transmit.c:200
int irrelevant(const struct dns_transmit *d, const char *buf, unsigned int len)
Definition: dns_transmit.c:51
int firsttcp(struct dns_transmit *d)
Definition: dns_transmit.c:250
char servers[QUERY_MAXIPLEN]
Definition: dnsfilter.c:54
struct line * x
uint32 scopes[QUERY_MAXNS]
Definition: dnsfilter.c:55
void out(const char *s, unsigned int len)
Definition: generic-conf.c:54
void d(const char *home, const char *subdir, int uid, int gid, int mode)
const char * server
Definition: rbldns.c:17