2
#include <sys/socket.h>
11
static int serverwantstcp(const char *buf,unsigned int len)
15
if (!dns_packet_copy(buf,len,0,out,12)) return 1;
16
if (out[2] & 2) return 1;
20
static int serverfailed(const char *buf,unsigned int len)
25
if (!dns_packet_copy(buf,len,0,out,12)) return 1;
28
if (rcode && (rcode != 3)) { errno = error_again; return 1; }
32
static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
38
pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
39
if (byte_diff(out,2,d->query + 2)) return 1;
40
if (out[4] != 0) return 1;
41
if (out[5] != 1) return 1;
44
pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
45
if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; }
48
pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
49
if (byte_diff(out,2,d->qtype)) return 1;
50
if (byte_diff(out + 2,2,DNS_C_IN)) return 1;
55
static void packetfree(struct dns_transmit *d)
57
if (!d->packet) return;
58
alloc_free(d->packet);
62
static void queryfree(struct dns_transmit *d)
64
if (!d->query) return;
69
static void socketfree(struct dns_transmit *d)
76
void dns_transmit_free(struct dns_transmit *d)
83
static int randombind(struct dns_transmit *d)
87
for (j = 0;j < 10;++j)
88
if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
90
if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
95
static const int timeouts[4] = { 1, 3, 11, 45 };
97
static int thisudp(struct dns_transmit *d)
103
while (d->udploop < 4) {
104
for (;d->curserver < 16;++d->curserver) {
105
ip = d->servers + 4 * d->curserver;
106
if (byte_diff(ip,4,"\0\0\0\0")) {
107
d->query[2] = dns_random(256);
108
d->query[3] = dns_random(256);
110
d->s1 = 1 + socket_udp();
111
if (!d->s1) { dns_transmit_free(d); return -1; }
112
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
114
if (socket_connect4(d->s1 - 1,ip,53) == 0)
115
if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
118
taia_uint(&d->deadline,timeouts[d->udploop]);
119
taia_add(&d->deadline,&d->deadline,&now);
132
dns_transmit_free(d); return -1;
135
static int firstudp(struct dns_transmit *d)
141
static int nextudp(struct dns_transmit *d)
147
static int thistcp(struct dns_transmit *d)
155
for (;d->curserver < 16;++d->curserver) {
156
ip = d->servers + 4 * d->curserver;
157
if (byte_diff(ip,4,"\0\0\0\0")) {
158
d->query[2] = dns_random(256);
159
d->query[3] = dns_random(256);
161
d->s1 = 1 + socket_tcp();
162
if (!d->s1) { dns_transmit_free(d); return -1; }
163
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
166
taia_uint(&d->deadline,10);
167
taia_add(&d->deadline,&d->deadline,&now);
168
if (socket_connect4(d->s1 - 1,ip,53) == 0) {
172
if ((errno == error_inprogress) || (errno == error_wouldblock)) {
181
dns_transmit_free(d); return -1;
184
static int firsttcp(struct dns_transmit *d)
190
static int nexttcp(struct dns_transmit *d)
196
int dns_transmit_start(struct dns_transmit *d,const char servers[64],int flagrecursive,const char *q,const char qtype[2],const char localip[4])
200
dns_transmit_free(d);
203
len = dns_domain_length(q);
204
d->querylen = len + 18;
205
d->query = alloc(d->querylen);
206
if (!d->query) return -1;
208
uint16_pack_big(d->query,len + 16);
209
byte_copy(d->query + 2,12,flagrecursive ? "\0\0\1\0\0\1\0\0\0\0\0\0" : "\0\0\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround");
210
byte_copy(d->query + 14,len,q);
211
byte_copy(d->query + 14 + len,2,qtype);
212
byte_copy(d->query + 16 + len,2,DNS_C_IN);
214
byte_copy(d->qtype,2,qtype);
215
d->servers = servers;
216
byte_copy(d->localip,4,localip);
218
d->udploop = flagrecursive ? 1 : 0;
220
if (len + 16 > 512) return firsttcp(d);
224
void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
228
switch(d->tcpstate) {
229
case 0: case 3: case 4: case 5:
230
x->events = IOPAUSE_READ;
233
x->events = IOPAUSE_WRITE;
237
if (taia_less(&d->deadline,deadline))
238
*deadline = d->deadline;
241
int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
252
if (taia_less(when,&d->deadline)) return 0;
253
errno = error_timeout;
254
if (d->tcpstate == 0) return nextudp(d);
258
if (d->tcpstate == 0) {
260
have attempted to send UDP query to each server udploop times
261
have sent query to curserver on UDP socket s
263
r = recv(fd,udpbuf,sizeof udpbuf,0);
265
if (errno == error_connrefused) if (d->udploop == 2) return 0;
268
if (r + 1 > sizeof udpbuf) return 0;
270
if (irrelevant(d,udpbuf,r)) return 0;
271
if (serverwantstcp(udpbuf,r)) return firsttcp(d);
272
if (serverfailed(udpbuf,r)) {
273
if (d->udploop == 2) return 0;
279
d->packet = alloc(d->packetlen);
280
if (!d->packet) { dns_transmit_free(d); return -1; }
281
byte_copy(d->packet,d->packetlen,udpbuf);
286
if (d->tcpstate == 1) {
288
have sent connection attempt to curserver on TCP socket s
291
if (!socket_connected(fd)) return nexttcp(d);
297
if (d->tcpstate == 2) {
299
have connection to curserver on TCP socket s
300
have sent pos bytes of query
302
r = write(fd,d->query + d->pos,d->querylen - d->pos);
303
if (r <= 0) return nexttcp(d);
305
if (d->pos == d->querylen) {
308
taia_uint(&d->deadline,10);
309
taia_add(&d->deadline,&d->deadline,&now);
315
if (d->tcpstate == 3) {
317
have sent entire query to curserver on TCP socket s
321
if (r <= 0) return nexttcp(d);
327
if (d->tcpstate == 4) {
329
have sent entire query to curserver on TCP socket s
331
have received one byte of packet length into packetlen
334
if (r <= 0) return nexttcp(d);
339
d->packet = alloc(d->packetlen);
340
if (!d->packet) { dns_transmit_free(d); return -1; }
344
if (d->tcpstate == 5) {
346
have sent entire query to curserver on TCP socket s
347
have received entire packet length into packetlen
349
have received pos bytes of packet
351
r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
352
if (r <= 0) return nexttcp(d);
354
if (d->pos < d->packetlen) return 0;
357
if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
358
if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
359
if (serverfailed(d->packet,d->packetlen)) return nexttcp(d);