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
);