5 adns_status
adns__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 (ctype_digit(c
) || 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 static void quproc_tosend_tcp(adns_state ads
, adns_query qu
, struct timeval now
) {
74 unsigned char length
[2];
77 length
[0]= (qu
->querylen
&0x0ff00U
) >>8;
78 length
[1]= (qu
->querylen
&0x0ff);
80 adns__tcp_tryconnect(ads
);
81 /* fixme: try sending queries as soon as server comes up */
82 /* fixme: use vbuf_ensure, and preallocate buffer space */
83 if (ads
->tcpstate
!= server_ok
) return;
85 DLIST_UNLINK(ads
->tosend
,qu
);
86 timevaladd(&now
,TCPMS
);
88 qu
->senttcpserver
= ads
->tcpserver
;
89 DLIST_LINKTAIL(ads
->timew
,qu
);
94 iov
[0].iovbase
= length
;
96 iov
[1].iovbase
= qu
->querymsg
;
97 iov
[1].iov_len
= qu
->querylen
;
98 r
= writev(ads
->tcpsocket
,iov
,2);
100 if (!(errno
== EAGAIN
|| errno
== EINTR
|| errno
== ENOSPC
||
101 errno
== ENOBUFS
|| errno
== ENOMEM
)) {
102 adns__tcp_broken(ads
,"write",strerror(errno
));
109 if (r
< qu
->querylen
+2) {
110 newopbufused
= qu
->opbufused
+ qu
->querylen
+ 2 - r
;
111 if (newopbufused
> ads
->opbufavail
) {
112 newopbufavail
= ads
->newopbufused
<<1;
113 newopbuf
= realloc(newopbufavail
);
115 DLIST_UNLINK(ads
->timew
,qu
);
116 query_fail(ads
,qu
,adns_s_nolocalmem
);
119 ads
->opbuf
= newopbuf
;
120 ads
->opbufavail
= newopbufavail
;
123 memcpy(ads
->opbuf
+ads
->opbufused
,length
+r
,2-r
);
124 ads
->opbufused
+= (2-r
);
129 memcpy(ads
->opbuf
+ads
->opbufused
,qu
->querymsg
+r
,qu
->querylen
-r
);
130 ads
->opbufused
= newopbufused
;
134 void adns__quproc_tosend(adns_state ads
, adns_query qu
, struct timeval now
) {
135 /* Query must be on the `tosend' queue, and we guarantee to remove it.
137 struct sockaddr_in servaddr
;
140 if (qu
->nextudpserver
== -1) { quproc_tosend_tcp(ads
,qu
,now
); return; }
141 if (qu
->querylen
> UDPMAXDGRAM
) {
142 qu
->nextudpserver
= -1;
143 quproc_tosend_tcp(ads
,qu
,now
);
147 if (qu
->udpretries
>= UDPMAXRETRIES
) {
148 DLIST_UNLINK(ads
->tosend
,qu
);
149 query_fail(ads
,qu
,adns_s_notresponding
);
153 serv
= qu
->nextudpserver
;
154 memset(&servaddr
,0,sizeof(servaddr
));
155 servaddr
.sin_family
= AF_INET
;
156 servaddr
.sin_addr
= ads
->servers
[serv
].addr
;
157 servaddr
.sin_port
= htons(NSPORT
);
159 r
= sendto(ads
->udpsocket
,qu
->querymsg
,qu
->querylen
,0,&servaddr
,sizeof(servaddr
));
160 if (r
<0 && errno
== EMSGSIZE
) {
161 qu
->nextudpserver
= -1;
162 quproc_tosend_tcp(ads
,qu
,now
); return;
164 if (r
<0) warn("sendto %s failed: %s",inet_ntoa(servaddr
.sin_addr
),strerror(errno
));
166 DLIST_UNLINK(ads
->tosend
,qu
);
167 timevaladd(&now
,UDPRETRYMS
);
169 qu
->sentudp
|= (1<<serv
);
170 qu
->nextudpserver
= (serv
+1)%ads
->nservers
;
172 DLIST_LINKTAIL(ads
->timew
,qu
);
175 void adns__query_fail(adns_state ads
, adns_query qu
, adns_status stat
) {
179 if (!ans
) ans
= malloc(sizeof(*qu
->answer
));
188 LIST_LINK_TAIL(ads
->output
,qu
);