Blob


1 #include <u.h>
2 #include <netinet/in.h>
3 #include <arpa/nameser.h>
4 #include <resolv.h>
5 #include <netdb.h>
6 #include <libc.h>
7 #include <ip.h>
8 #include <bio.h>
9 #include <ndb.h>
10 #include "ndbhf.h"
12 static void nstrcpy(char*, char*, int);
13 static void mkptrname(char*, char*, int);
14 static Ndbtuple *doquery(char*, char*);
16 /*
17 * Run a DNS lookup for val/type on net.
18 */
19 Ndbtuple*
20 dnsquery(char *net, char *val, char *type)
21 {
22 static int init;
23 char rip[128];
24 Ndbtuple *t;
26 USED(net);
28 if(!init){
29 init = 1;
30 fmtinstall('I', eipfmt);
31 }
32 /* give up early on stupid questions - vwhois */
33 if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0)
34 return nil;
36 /* zero out the error string */
37 werrstr("");
39 /* if this is a reverse lookup, first look up the domain name */
40 if(strcmp(type, "ptr") == 0){
41 mkptrname(val, rip, sizeof rip);
42 t = doquery(rip, "ptr");
43 }else
44 t = doquery(val, type);
46 return t;
47 }
49 /*
50 * convert address into a reverse lookup address
51 */
52 static void
53 mkptrname(char *ip, char *rip, int rlen)
54 {
55 char buf[128];
56 char *p, *np;
57 int len;
59 if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){
60 nstrcpy(rip, ip, rlen);
61 return;
62 }
64 nstrcpy(buf, ip, sizeof buf);
65 for(p = buf; *p; p++)
66 ;
67 *p = '.';
68 np = rip;
69 len = 0;
70 while(p >= buf){
71 len++;
72 p--;
73 if(*p == '.'){
74 memmove(np, p+1, len);
75 np += len;
76 len = 0;
77 }
78 }
79 memmove(np, p+1, len);
80 np += len;
81 strcpy(np, "in-addr.arpa");
82 }
84 static void
85 nstrcpy(char *to, char *from, int len)
86 {
87 strncpy(to, from, len);
88 to[len-1] = 0;
89 }
91 /*
92 * Disgusting, ugly interface to libresolv,
93 * which everyone seems to have.
94 */
95 enum
96 {
97 MAXRR = 100,
98 MAXDNS = 4096,
100 /* RR types */
101 Ta= 1,
102 Tns= 2,
103 Tmd= 3,
104 Tmf= 4,
105 Tcname= 5,
106 Tsoa= 6,
107 Tmb= 7,
108 Tmg= 8,
109 Tmr= 9,
110 Tnull= 10,
111 Twks= 11,
112 Tptr= 12,
113 Thinfo= 13,
114 Tminfo= 14,
115 Tmx= 15,
116 Ttxt= 16,
117 Trp= 17,
118 Tsig= 24,
119 Tkey= 25,
120 Taaaa= 28,
121 Tcert= 37,
123 /* query types (all RR types are also queries) */
124 Tixfr= 251, /* incremental zone transfer */
125 Taxfr= 252, /* zone transfer */
126 Tmailb= 253, /* { Tmb, Tmg, Tmr } */
127 Tall= 255, /* all records */
129 /* classes */
130 Csym= 0, /* internal symbols */
131 Cin= 1, /* internet */
132 Ccs, /* CSNET (obsolete) */
133 Cch, /* Chaos net */
134 Chs, /* Hesiod (?) */
136 /* class queries (all class types are also queries) */
137 Call= 255, /* all classes */
139 };
142 static int name2type(char*);
143 static uchar *skipquestion(uchar*, uchar*, uchar*, int);
144 static uchar *unpack(uchar*, uchar*, uchar*, Ndbtuple**, int);
145 static uchar *rrnext(uchar*, uchar*, uchar*, Ndbtuple**);
146 static Ndbtuple *rrunpack(uchar*, uchar*, uchar**, char*, ...);
148 static Ndbtuple*
149 doquery(char *name, char *type)
151 int n, nstype;
152 uchar *buf, *p;
153 Ndbtuple *t;
154 int qdcount, ancount;
156 if((nstype = name2type(type)) < 0){
157 werrstr("unknown dns type %s", type);
158 return nil;
161 buf = malloc(MAXDNS);
162 if(buf == nil)
163 return nil;
165 if((n = res_search(name, Cin, nstype, buf, MAXDNS)) < 0){
166 free(buf);
167 return nil;
169 if(n >= MAXDNS){
170 free(buf);
171 werrstr("too much dns information");
172 return nil;
175 qdcount = (buf[4]<<8)|buf[5];
176 ancount = (buf[6]<<8)|buf[7];
178 p = buf+12;
179 p = skipquestion(buf, buf+n, p, qdcount);
180 p = unpack(buf, buf+n, p, &t, ancount);
181 USED(p);
182 return t;
185 static struct {
186 char *s;
187 int t;
188 } dnsnames[] =
190 "ip", Ta,
191 "ns", Tns,
192 "md", Tmd,
193 "mf", Tmf,
194 "cname", Tcname,
195 "soa", Tsoa,
196 "mb", Tmb,
197 "mg", Tmg,
198 "mr", Tmr,
199 "null", Tnull,
200 "ptr", Tptr,
201 "hinfo", Thinfo,
202 "minfo", Tminfo,
203 "mx", Tmx,
204 "txt", Ttxt,
205 "rp", Trp,
206 "key", Tkey,
207 "cert", Tcert,
208 "sig", Tsig,
209 "aaaa", Taaaa,
210 "ixfr", Tixfr,
211 "axfr", Taxfr,
212 "all", Call,
213 };
215 static char*
216 type2name(int t)
218 int i;
220 for(i=0; i<nelem(dnsnames); i++)
221 if(dnsnames[i].t == t)
222 return dnsnames[i].s;
223 return nil;
226 static int
227 name2type(char *name)
229 int i;
231 for(i=0; i<nelem(dnsnames); i++)
232 if(strcmp(name, dnsnames[i].s) == 0)
233 return dnsnames[i].t;
234 return -1;
237 static uchar*
238 skipquestion(uchar *buf, uchar *ebuf, uchar *p, int n)
240 int i, len;
241 char tmp[100];
243 for(i=0; i<n; i++){
244 if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) <= 0)
245 return nil;
246 p += 4+len;
248 return p;
251 static uchar*
252 unpack(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt, int n)
254 int i;
255 Ndbtuple *first, *last, *t;
257 *tt = nil;
258 first = nil;
259 last = nil;
260 for(i=0; i<n; i++){
261 if((p = rrnext(buf, ebuf, p, &t)) == nil){
262 if(first)
263 ndbfree(first);
264 return nil;
266 if(t == nil) /* unimplemented rr type */
267 continue;
268 if(last)
269 last->entry = t;
270 else
271 first = t;
272 for(last=t; last->entry; last=last->entry)
273 last->line = last->entry;
274 last->line = t;
276 *tt = first;
277 return p;
280 #define G2(p) nhgets(p)
281 #define G4(p) nhgetl(p)
283 static uchar*
284 rrnext(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt)
286 char tmp[Ndbvlen];
287 char b[MAXRR];
288 uchar ip[IPaddrlen];
289 int len;
290 Ndbtuple *first, *t;
291 int rrtype;
292 int rrlen;
294 first = nil;
295 t = nil;
296 *tt = nil;
297 if(p == nil)
298 return nil;
300 if((len = dn_expand(buf, ebuf, p, b, sizeof b)) < 0){
301 corrupt:
302 werrstr("corrupt dns packet");
303 if(first)
304 ndbfree(first);
305 return nil;
307 p += len;
309 rrtype = G2(p);
310 rrlen = G2(p+8);
311 p += 10;
313 if(rrtype == Tptr)
314 first = ndbnew("ptr", b);
315 else
316 first = ndbnew("dom", b);
318 switch(rrtype){
319 default:
320 goto end;
321 case Thinfo:
322 t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os");
323 break;
324 case Tminfo:
325 t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox");
326 break;
327 case Tmx:
328 t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx");
329 break;
330 case Tcname:
331 case Tmd:
332 case Tmf:
333 case Tmg:
334 case Tmr:
335 case Tmb:
336 case Tns:
337 case Tptr:
338 case Trp:
339 t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype));
340 break;
341 case Ta:
342 if(rrlen != IPv4addrlen)
343 goto corrupt;
344 memmove(ip, v4prefix, IPaddrlen);
345 memmove(ip+IPv4off, p, IPv4addrlen);
346 snprint(tmp, sizeof tmp, "%I", ip);
347 t = ndbnew("ip", tmp);
348 p += rrlen;
349 break;
350 case Taaaa:
351 if(rrlen != IPaddrlen)
352 goto corrupt;
353 snprint(tmp, sizeof tmp, "%I", ip);
354 t = ndbnew("ip", tmp);
355 p += rrlen;
356 break;
357 case Tnull:
358 snprint(tmp, sizeof tmp, "%.*H", rrlen, p);
359 t = ndbnew("null", tmp);
360 p += rrlen;
361 break;
362 case Ttxt:
363 t = rrunpack(buf, ebuf, &p, "Y", "txt");
364 break;
366 case Tsoa:
367 t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox",
368 "serial", "refresh", "retry", "expire", "ttl");
369 break;
371 case Tkey:
372 t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key");
373 break;
375 case Tsig:
376 t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels",
377 "ttl", "exp", "incep", "tag", "signer", "sig");
378 break;
380 case Tcert:
381 t = rrunpack(buf, ebuf, &p, "SSCY", "type", "tag", "alg", "cert");
382 break;
384 if(t == nil)
385 goto corrupt;
387 end:
388 first->entry = t;
389 *tt = first;
390 return p;
393 static Ndbtuple*
394 rrunpack(uchar *buf, uchar *ebuf, uchar **pp, char *fmt, ...)
396 char *name;
397 int len, n;
398 uchar *p;
399 va_list arg;
400 Ndbtuple *t, *first, *last;
401 char tmp[Ndbvlen];
403 p = *pp;
404 va_start(arg, fmt);
405 first = nil;
406 last = nil;
407 for(; *fmt; fmt++){
408 name = va_arg(arg, char*);
409 switch(*fmt){
410 default:
411 return nil;
412 case 'C':
413 snprint(tmp, sizeof tmp, "%d", *p++);
414 break;
415 case 'S':
416 snprint(tmp, sizeof tmp, "%d", G2(p));
417 p += 2;
418 break;
419 case 'L':
420 snprint(tmp, sizeof tmp, "%d", G4(p));
421 p += 4;
422 break;
423 case 'N':
424 if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) < 0)
425 return nil;
426 p += len;
427 break;
428 case 'Y':
429 len = *p++;
430 n = len;
431 if(n >= sizeof tmp)
432 n = sizeof tmp-1;
433 memmove(tmp, p, n);
434 p += len;
435 tmp[n] = 0;
436 break;
438 t = ndbnew(name, tmp);
439 if(last)
440 last->entry = t;
441 else
442 first = t;
443 last = t;
445 *pp = p;
446 return first;