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