7 #include <sys/socket.h>
8 #include <sys/select.h>
10 #include <netinet/in.h>
16 #include "stdio_impl.h"
20 #define PACKET_MAX 512
21 #define PTR_MAX (64 + sizeof ".in-addr.arpa")
23 int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
28 unsigned char _buf[64];
29 char line[64], *s, *z;
31 struct sockaddr_in sin;
32 struct sockaddr_in6 sin6;
33 } sa = {0}, ns[3] = {{0}};
36 int family = AF_UNSPEC;
37 unsigned char q[280] = "", *r = dest;
40 int got = 0, failed = 0;
41 int errcode = EAI_AGAIN;
48 /* Construct query template - RR and ID will be filled later */
49 if (strlen(name)-1 >= 254U) return EAI_NONAME;
51 strcpy((char *)q+13, name);
52 for (i=13; q[i]; i=j+1) {
53 for (j=i; q[j] && q[j] != '.'; j++);
54 if (j-i-1u > 62u) return EAI_NONAME;
60 /* Make a reasonably unpredictable id */
62 id = tv.tv_usec + tv.tv_usec/256 & 0xffff;
64 /* Get nameservers from resolv.conf, fallback to localhost */
65 f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
66 if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
67 if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
69 for (s=line+11; isspace(*s); s++);
70 for (z=s; *z && !isspace(*z); z++);
72 if (__ipparse(ns+nns, family, s) < 0) continue;
73 ns[nns].sin.sin_port = htons(53);
74 family = ns[nns++].sin.sin_family;
75 sl = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
77 if (f) __fclose_ca(f);
79 ns[0].sin.sin_family = AF_INET;
80 ns[0].sin.sin_port = htons(53);
85 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
87 /* Get local address and open/bind a socket */
88 sa.sin.sin_family = family;
89 fd = socket(family, SOCK_DGRAM, 0);
90 if (bind(fd, (void *)&sa, sl) < 0) {
94 /* Nonblocking to work around Linux UDP select bug */
95 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
97 /* Loop until we timeout; break early on success */
98 for (; time(0)-t0 < TIMEOUT; ) {
100 /* Query all configured namservers in parallel */
101 for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) {
105 sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl);
108 /* Wait for a response, or until time to retry */
113 if (select(fd+1, &fds, 0, 0, &tv) <= 0) continue;
115 /* Process any and all replies */
116 while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0,
117 (void *)&sa, (socklen_t[1]){sl})) >= 2)
119 /* Ignore replies from addresses we didn't send to */
120 for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break;
121 if (i==nns) continue;
123 /* Compute index of the query from id */
124 i = r[0]*256+r[1] - id & 0xffff;
125 if ((unsigned)i >= rrcnt || !rr[i]) continue;
127 /* Interpret the result code */
133 if (1) errcode = EAI_NONAME; else
139 /* Mark this record as answered */
144 /* Check to see if we have answers to all queries */
145 if (got+failed == rrcnt) break;
149 pthread_setcancelstate(cs, 0);
151 /* Return the number of results, or an error code if none */
156 static void mkptr4(char *s, const unsigned char *ip)
158 sprintf(s, "%d.%d.%d.%d.in-addr.arpa",
159 ip[3], ip[2], ip[1], ip[0]);
162 static void mkptr6(char *s, const unsigned char *ip)
164 static const char xdigits[] = "0123456789abcdef";
166 for (i=15; i>=0; i--) {
167 *s++ = xdigits[ip[i]&15]; *s++ = '.';
168 *s++ = xdigits[ip[i]>>4]; *s++ = '.';
170 strcpy(s, "ip6.arpa");
173 int __dns_query(unsigned char *r, const void *a, int family, int ptr)
176 int rr[2], rrcnt = 1;
179 if (family == AF_INET6) mkptr6(buf, a);
183 } else if (family == AF_INET6) {
187 if (family != AF_INET) rr[rrcnt++] = RR_AAAA;
190 return __dns_doqueries(r, a, rr, rrcnt);
194 #define BITOP(a,b,op) \
195 ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
197 static int decname(char *s, const unsigned char *b, const unsigned char *p)
199 /* Remember jump destinations to detect loops and abort */
200 size_t seen[PACKET_MAX/8/sizeof(size_t)] = { 0 };
201 char *sz = s + HOST_NAME_MAX;
202 const unsigned char *pz = b+512;
204 if (p>=pz) return -1;
206 int j = (p[0]&1) | p[1];
207 if (BITOP(seen, j, &)) return -1;
211 if (p+*p+1>=pz || s+*p>=sz) return -1;
215 s[-1] = *p ? '.' : 0;
220 int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec)
222 int qdcount, ancount;
223 const unsigned char *p;
228 if ((r[3]&15)) return 0;
230 qdcount = r[4]*256 + r[5];
231 ancount = r[6]*256 + r[7];
232 if (qdcount+ancount > 64) return -1;
234 while (p-r < 512 && *p-1U < 127) p++;
235 if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
240 while (p-r < 512 && *p-1U < 127) p++;
241 if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
244 len = p[8]*256 + p[9];
245 if (p+len > r+512) return -1;
246 if (p[1]==rr && len <= maxlen) {
247 if (dec && decname(tmp, r, p+10)<0) return -1;
249 if (dec) strcpy(dest, tmp);
250 else memcpy(dest, p+10, len);
251 dest = (char *)dest + stride;
261 int __dns_count_addrs(const unsigned char *r, int cnt)
264 static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } };
267 for (i=0; i<2; i++) {
268 res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0);
269 if (res < 0) return res;