3 #include "adns-internal.h"
5 static adns_status
mkquery(adns_state ads
, const char *owner
, int ol
, int id
,
6 adns_rrtype type
, adns_queryflags flags
, int *qml_r
) {
7 int ll
, c
, nlabs
, qbufreq
;
8 unsigned char label
[255], *nqbuf
;
11 #define MKQUERY_ADDB(b) *nqbuf++= (b)
12 #define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff))
14 qbufreq
= 12+strlen(owner
)+3;
15 if (ads
->qbufavail
< qbufreq
) {
16 nqbuf
= realloc(ads
->qbuf
,qbufreq
);
17 if (!nqbuf
) return adns_s_nolocalmem
;
18 ads
->qbuf
= nqbuf
; ads
->qbufavail
= qbufreq
;
23 MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
24 MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
25 MKQUERY_ADDW(1); /* QDCOUNT=1 */
26 MKQUERY_ADDW(0); /* ANCOUNT=0 */
27 MKQUERY_ADDW(0); /* NSCOUNT=0 */
28 MKQUERY_ADDW(0); /* ARCOUNT=0 */
29 p
= owner
; pe
= owner
+ol
;
31 if (!*p
) return adns_s_invaliddomain
;
34 while (p
!=pe
&& (c
= *p
++)!='.') {
36 if (!(flags
& adns_f_anyquote
)) return adns_s_invaliddomain
;
37 if (ctype_digit(p
[0])) {
38 if (ctype_digit(p
[1]) && ctype_digit(p
[2])) {
39 c
= (*p
++ - '0')*100 + (*p
++ - '0')*10 + (*p
++ - '0');
40 if (c
>= 256) return adns_s_invaliddomain
;
42 return adns_s_invaliddomain
;
44 } else if (!(c
= *p
++)) {
45 return adns_s_invaliddomain
;
48 if (!(flags
& adns_f_anyquote
)) {
49 if ((c
>= '0' && c
<= '9') || c
== '-') {
50 if (!ll
) return adns_s_invaliddomain
;
51 } else if ((c
< 'a' || c
> 'z') && (c
< 'A' && c
> 'Z')) {
52 return adns_s_invaliddomain
;
55 if (ll
== sizeof(label
)) return adns_s_invaliddomain
;
58 if (!ll
) return adns_s_invaliddomain
;
59 if (nlabs
++ > 63) return adns_s_invaliddomain
;
61 memcpy(nqbuf
,label
,ll
); nqbuf
+= ll
;
65 MKQUERY_ADDW(type
& adns__rrt_typemask
); /* QTYPE */
66 MKQUERY_ADDW(1); /* QCLASS=IN */
68 *qml_r
= nqbuf
- ads
->qbuf
;
73 void adns__quproc_tosend(adns_state ads
, adns_query qu
, struct timeval now
) {
74 /* Query must be on the `tosend' queue, and guarantees to remove it.
75 * fixme: Do not send more than 512-byte udp datagrams
77 struct sockaddr_in servaddr
;
80 if (qu
->nextudpserver
!= -1) {
81 if (qu
->udpretries
>= UDPMAXRETRIES
) {
82 DLIST_UNLINK(ads
->tosend
,qu
);
83 query_fail(ads
,qu
,adns_s_notresponding
);
86 serv
= qu
->nextudpserver
;
87 memset(&servaddr
,0,sizeof(servaddr
));
88 servaddr
.sin_family
= AF_INET
;
89 servaddr
.sin_addr
= ads
->servers
[serv
].addr
;
90 servaddr
.sin_port
= htons(NSPORT
);
91 r
= sendto(ads
->udpsocket
,qu
->querymsg
,qu
->querylen
,0,&servaddr
,sizeof(servaddr
));
92 if (r
<0 && errno
== EMSGSIZE
) {
93 qu
->nextudpserver
= -1;
96 warn("sendto %s failed: %s",inet_ntoa(servaddr
.sin_addr
),strerror(errno
));
98 DLIST_UNLINK(ads
->tosend
,qu
);
99 timevaladd(&now
,UDPRETRYMS
);
101 qu
->sentudp
|= (1<<serv
);
102 qu
->nextudpserver
= (serv
+1)%ads
->nservers
;
104 DLIST_LINKTAIL(ads
->timew
,qu
);
109 /* fixme: TCP queries preceded by length */
111 adns__tcp_tryconnect(ads
);
112 /* fixme: make this work properly */
113 serv
= tcpserver_get(ads
);
114 if (serv
<0) { r
=0; break; }
115 if (ads
->opbufused
) { r
=0; break; }
116 r
= write(ads
->tcpsocket
,qu
->querymsg
,qu
->querylen
);
118 if (errno
== EAGAIN
|| errno
== EINTR
|| errno
== ENOSPC
||
119 errno
== ENOBUFS
|| errno
== ENOMEM
) {
122 tcpserver_broken(serv
);
124 if (r
< qu
->querylen
) {
125 newopbufused
= qu
->opbufused
+ (qu
->querylen
-r
);
126 if (newopbufused
> ads
->opbufavail
) {
127 newopbufavail
= ads
->newopbufused
<<1;
128 newopbuf
= realloc(newopbufavail
);
130 DLIST_UNLINK(ads
->tosend
,qu
);
131 query_fail(ads
,qu
,adns_s_nolocalmem
);
134 ads
->opbuf
= newopbuf
;
135 ads
->opbufavail
= newopbufavail
;
137 memcpy(ads
->opbuf
+ads
->opbufused
,qu
->querymsg
+r
,qu
->querylen
-r
);
138 ads
->opbufused
= newopbufused
;
140 DLIST_UNLINK(ads
->tosend
,qu
);
141 timevaladd(&now
,TCPMS
);
143 qu
->senttcp
|= (1<<qu
->nextserver
);
144 DLIST_LINKTAIL(ads
->timew
,qu
);
147 void adns__query_fail(adns_state ads
, adns_query qu
, adns_status stat
) {
151 if (!ans
) ans
= malloc(sizeof(*qu
->answer
));
160 LIST_LINK_TAIL(ads
->output
,qu
);