djbdnscurve6 45
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 DNSPORT 53
14#define MAXUDPLOOP 5 // smaller values possible here; larger not
15
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 UDP 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 return thistcp(d);
254}
255
256int nexttcp(struct dns_transmit *d)
257{
258 ++d->curserver;
259 return thistcp(d);
260}
261
262/* Legacy calls */
263
265 int flagrecursive,const char *q,const char qtype[2],const char localip[16])
266{
267 return cns_transmit_start(d,servers,flagrecursive,q,qtype,localip,0,0,0);
268}
269
271 int flagrecursive,const char *q,const char qtype[2], \
272 const char localip[16],const uint32 scopes[QUERY_MAXNS])
273{
274 byte_copy(scope_ids,128,scopes);
275
276 return cns_transmit_start(d,servers,flagrecursive,q,qtype,localip,0,0,0);
277}
278
279void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
280{
281 x->fd = d->s1 - 1;
282
283 switch (d->tcpstate) {
284 case 0: case 3: case 4: case 5:
285 x->events = IOPAUSE_READ;
286 break;
287 case 1: case 2:
288 x->events = IOPAUSE_WRITE;
289 break;
290 }
291
292 if (taia_less(&d->deadline,deadline))
293 *deadline = d->deadline;
294}
295
296int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
297{
298 char udpbuf[MSGSIZE + 1];
299 unsigned char ch;
300 int r;
301 int fd;
302 unsigned int len;
303
304 errno = EIO;
305 fd = d->s1 - 1;
306
307 if (!x->revents) {
308 if (taia_less((struct taia *)when,&d->deadline)) return 0;
309 errno = ETIMEDOUT;
310 if (d->tcpstate == 0) return nextudp(d);
311 return nexttcp(d);
312 }
313
314/*
315have attempted to send UDP query to each server udploop times
316have sent query to curserver on UDP socket s
317*/
318 if (d->tcpstate == 0) {
319 r = recv(fd,udpbuf,sizeof(udpbuf),0);
320 if (r <= 0) {
321 if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
322 return nextudp(d);
323 }
324 if (r + 1 > sizeof(udpbuf)) return 0;
325 len = r;
326
327 if (cns_uncurve(d,udpbuf,&len)) return nextudp(d); // skipping wrong answering CurveDNS NS
328 if (irrelevant(d,udpbuf,len)) return nextudp(d);
329 if (serverwantstcp(udpbuf,len)) return firsttcp(d);
330 if (serverfailed(udpbuf,r,(char *)(d->servers + 16 * d->curserver))) {
331 if (d->udploop == 2) return 0;
332 return nextudp(d);
333 }
334 socketfree(d);
335
336 d->packetlen = len;
337 d->packet = alloc(d->packetlen);
338 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
339 byte_copy(d->packet,d->packetlen,udpbuf);
340 queryfree(d);
341 return 1;
342 }
343
344/*
345have sent connection attempt to curserver on TCP socket s
346pos not defined
347*/
348 if (d->tcpstate == 1) {
349 if (!socket_connected(fd)) return nexttcp(d);
350 d->pos = 0;
351 d->tcpstate = 2;
352 return 0;
353 }
354
355/*
356have connection to curserver on TCP socket s
357have sent pos bytes of query
358*/
359 if (d->tcpstate == 2) {
360 r = write(fd,d->query + d->pos,d->querylen - d->pos);
361 if (r <= 0) return nexttcp(d);
362 d->pos += r;
363 if (d->pos == d->querylen) {
364 struct taia now;
365 taia_now(&now);
366 taia_uint(&d->deadline,10);
367 taia_add(&d->deadline,&d->deadline,&now);
368 d->tcpstate = 3;
369 }
370 return 0;
371 }
372
373/*
374have sent entire query to curserver on TCP socket s
375pos not defined
376*/
377 if (d->tcpstate == 3) {
378 r = read(fd,&ch,1);
379 if (r <= 0) return nexttcp(d);
380 d->packetlen = ch;
381 d->tcpstate = 4;
382 return 0;
383 }
384
385/*
386have sent entire query to curserver on TCP socket s
387pos not defined
388have received one byte of packet length into packetlen
389*/
390 if (d->tcpstate == 4) {
391 r = read(fd,&ch,1);
392 if (r <= 0) return nexttcp(d);
393 d->packetlen <<= 8;
394 d->packetlen += ch;
395 d->tcpstate = 5;
396 d->pos = 0;
397 d->packet = alloc(d->packetlen);
398 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
399 return 0;
400 }
401
402/*
403have sent entire query to curserver on TCP socket s
404have received entire packet length into packetlen
405packet is allocated
406have received pos bytes of packet
407*/
408 if (d->tcpstate == 5) {
409 r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
410 if (r <= 0) return nexttcp(d);
411 d->pos += r;
412 if (d->pos < d->packetlen) return 0;
413
414 socketfree(d);
415 if (cns_uncurve(d,d->packet,&d->packetlen)) return nexttcp(d);
416 if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
417 if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
418 if (serverfailed(d->packet,d->packetlen,(char *)(d->servers + 16 * d->curserver)))
419 return nexttcp(d);
420
421 queryfree(d);
422 return 1;
423 }
424
425 return 0;
426}
int fd
Definition: axfr-get.c:103
struct tai now
Definition: axfrdns.c:129
char ip[16]
Definition: axfrdns.c:125
uint16 len
Definition: axfrdns.c:319
char buf[MSGSIZE]
Definition: axfrdns.c:318
int cns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16], const char keys[1024], const char pubkey[32], const char *suffix)
Definition: curvedns.c:246
void cns_query(struct dns_transmit *d)
Definition: curvedns.c:52
int cns_uncurve(const struct dns_transmit *d, char *buf, unsigned int *lenp)
Definition: curvedns.c:104
unsigned int fallback
Definition: curvedns.c:23
#define QUERY_MAXIPLEN
Definition: dns.h:45
#define DNS_C_IN
Definition: dns.h:53
#define MSGSIZE
Definition: dns.h:38
#define QUERY_MAXNS
Definition: dns.h:44
#define DNS_COM
Definition: dns.h:33
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:56
void dns_transmit_io(struct dns_transmit *d, iopause_fd *x, struct taia *deadline)
Definition: dns_transmit.c:279
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
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 dns_transmit_start6(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16], const uint32 scopes[QUERY_MAXNS])
Definition: dns_transmit.c:270
int nexttcp(struct dns_transmit *d)
Definition: dns_transmit.c:256
int serverwantstcp(const char *buf, unsigned int len)
Definition: dns_transmit.c:29
#define MAXUDPLOOP
Definition: dns_transmit.c:14
uint32 scope_ids[QUERY_MAXNS]
Definition: dns_transmit.c:16
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
int dns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16])
Definition: dns_transmit.c:264
#define DNSPORT
Definition: dns_transmit.c:13
int dns_transmit_get(struct dns_transmit *d, const iopause_fd *x, const struct taia *when)
Definition: dns_transmit.c:296
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:48
struct line * x
uint32 scopes[QUERY_MAXNS]
Definition: dnsfilter.c:49
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)