4 #include <netinet/in.h>
5 #include <arpa/nameser.h>
8 extern int res_query();
9 extern int res_search();
21 static unsigned short getshort(c) unsigned char *c;
22 { unsigned short u; u = c[0]; return (u << 8) + c[1]; }
24 static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response;
25 static int responselen;
26 static unsigned char *responseend;
27 static unsigned char *responsepos;
29 static int numanswers;
30 static char name[MAXDNAME];
31 static struct ip_address ip;
34 static stralloc glue = {0};
36 static int (*lookup)() = res_query;
38 static int resolve(domain,type)
46 if (!stralloc_copy(&glue,domain)) return DNS_MEM;
47 if (!stralloc_0(&glue)) return DNS_MEM;
48 responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response));
51 if (errno == ECONNREFUSED) return DNS_SOFT;
52 if (h_errno == TRY_AGAIN) return DNS_SOFT;
55 if (responselen >= sizeof(response))
56 responselen = sizeof(response);
57 responseend = response.buf + responselen;
58 responsepos = response.buf + sizeof(HEADER);
59 n = ntohs(response.hdr.qdcount);
62 i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
63 if (i < 0) return DNS_SOFT;
65 i = responseend - responsepos;
66 if (i < QFIXEDSZ) return DNS_SOFT;
67 responsepos += QFIXEDSZ;
69 numanswers = ntohs(response.hdr.ancount);
73 static int findname(wanttype)
76 unsigned short rrtype;
77 unsigned short rrdlen;
80 if (numanswers <= 0) return 2;
82 if (responsepos == responseend) return DNS_SOFT;
84 i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
85 if (i < 0) return DNS_SOFT;
88 i = responseend - responsepos;
89 if (i < 4 + 3 * 2) return DNS_SOFT;
91 rrtype = getshort(responsepos);
92 rrdlen = getshort(responsepos + 8);
95 if (rrtype == wanttype)
97 if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0)
99 responsepos += rrdlen;
103 responsepos += rrdlen;
107 static int findip(wanttype)
110 unsigned short rrtype;
111 unsigned short rrdlen;
114 if (numanswers <= 0) return 2;
116 if (responsepos == responseend) return DNS_SOFT;
118 i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
119 if (i < 0) return DNS_SOFT;
122 i = responseend - responsepos;
123 if (i < 4 + 3 * 2) return DNS_SOFT;
125 rrtype = getshort(responsepos);
126 rrdlen = getshort(responsepos + 8);
129 if (rrtype == wanttype)
133 ip.d[0] = responsepos[0];
134 ip.d[1] = responsepos[1];
135 ip.d[2] = responsepos[2];
136 ip.d[3] = responsepos[3];
137 responsepos += rrdlen;
141 responsepos += rrdlen;
145 static int findmx(wanttype)
148 unsigned short rrtype;
149 unsigned short rrdlen;
152 if (numanswers <= 0) return 2;
154 if (responsepos == responseend) return DNS_SOFT;
156 i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
157 if (i < 0) return DNS_SOFT;
160 i = responseend - responsepos;
161 if (i < 4 + 3 * 2) return DNS_SOFT;
163 rrtype = getshort(responsepos);
164 rrdlen = getshort(responsepos + 8);
167 if (rrtype == wanttype)
171 pref = (responsepos[0] << 8) + responsepos[1];
172 if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0)
174 responsepos += rrdlen;
178 responsepos += rrdlen;
182 void dns_init(flagsearch)
186 if (flagsearch) lookup = res_search;
194 for (loop = 0;loop < 10;++loop)
196 if (!sa->len) return loop;
197 if (sa->s[sa->len - 1] == ']') return loop;
198 if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
199 switch(resolve(sa,T_ANY))
201 case DNS_MEM: return DNS_MEM;
202 case DNS_SOFT: return DNS_SOFT;
203 case DNS_HARD: return loop;
205 while ((r = findname(T_CNAME)) != 2)
207 if (r == DNS_SOFT) return DNS_SOFT;
210 if (!stralloc_copys(sa,name)) return DNS_MEM;
214 if (r == 2) return loop;
217 return DNS_HARD; /* alias loop */
222 static int iaafmt(s,ip)
224 struct ip_address *ip;
229 i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
230 i = fmt_str(s,"."); len += i; if (s) s += i;
231 i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
232 i = fmt_str(s,"."); len += i; if (s) s += i;
233 i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
234 i = fmt_str(s,"."); len += i; if (s) s += i;
235 i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
236 i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i;
242 struct ip_address *ip;
246 if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
247 sa->len = iaafmt(sa->s,ip);
248 switch(resolve(sa,T_PTR))
250 case DNS_MEM: return DNS_MEM;
251 case DNS_SOFT: return DNS_SOFT;
252 case DNS_HARD: return DNS_HARD;
254 while ((r = findname(T_PTR)) != 2)
256 if (r == DNS_SOFT) return DNS_SOFT;
259 if (!stralloc_copys(sa,name)) return DNS_MEM;
266 static int dns_ipplus(ia,sa,pref)
274 if (sa->len && (sa->s[0] == '['))
276 if (!stralloc_copy(&glue,sa)) return DNS_MEM;
277 if (!stralloc_0(&glue)) return DNS_MEM;
279 if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
281 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
286 switch(resolve(sa,T_A))
288 case DNS_MEM: return DNS_MEM;
289 case DNS_SOFT: return DNS_SOFT;
290 case DNS_HARD: return DNS_HARD;
292 while ((r = findip(T_A)) != 2)
296 if (r == DNS_SOFT) return DNS_SOFT;
298 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
307 if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
309 return dns_ipplus(ia,sa,0);
312 int dns_mxip(ia,sa,random)
315 unsigned long random;
318 struct mx { stralloc sa; unsigned short p; } *mx;
324 if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
327 if (sa->len && (sa->s[0] == '['))
330 if (!stralloc_copy(&glue,sa)) return DNS_MEM;
331 if (!stralloc_0(&glue)) return DNS_MEM;
333 if (!glue.s[ip_scanbracket(glue.s,&ix.ip)])
335 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
340 switch(resolve(sa,T_MX))
342 case DNS_MEM: return DNS_MEM;
343 case DNS_SOFT: return DNS_SOFT;
344 case DNS_HARD: return dns_ip(ia,sa);
347 mx = (struct mx *) alloc(numanswers * sizeof(struct mx));
348 if (!mx) return DNS_MEM;
351 while ((r = findmx(T_MX)) != 2)
353 if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; }
358 if (!stralloc_copys(&mx[nummx].sa,name))
360 while (nummx > 0) alloc_free(mx[--nummx].sa.s);
361 alloc_free(mx); return DNS_MEM;
367 if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */
372 unsigned long numsame;
376 for (j = 1;j < nummx;++j)
377 if (mx[j].p < mx[i].p)
382 else if (mx[j].p == mx[i].p)
385 random = random * 69069 + 1;
386 if ((random / 2) < (2147483647 / numsame))
390 switch(dns_ipplus(ia,&mx[i].sa,mx[i].p))
392 case DNS_MEM: case DNS_SOFT:
396 alloc_free(mx[i].sa.s);