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-1);
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 */
138 };
141 static int name2type(char*);
142 static uchar *skipquestion(uchar*, uchar*, uchar*, int);
143 static uchar *unpack(uchar*, uchar*, uchar*, Ndbtuple**, int);
144 static uchar *rrnext(uchar*, uchar*, uchar*, Ndbtuple**);
145 static Ndbtuple *rrunpack(uchar*, uchar*, uchar**, char*, ...);
147 static Ndbtuple*
148 doquery(char *name, char *type)
150 int n, nstype;
151 uchar *buf, *p;
152 Ndbtuple *t;
153 int qdcount, ancount;
155 if((nstype = name2type(type)) < 0){
156 werrstr("unknown dns type %s", type);
157 return nil;
160 buf = malloc(MAXDNS);
161 if(buf == nil)
162 return nil;
164 if((n = res_search(name, Cin, nstype, buf, MAXDNS)) < 0){
165 free(buf);
166 return nil;
168 if(n >= MAXDNS){
169 free(buf);
170 werrstr("too much dns information");
171 return nil;
174 qdcount = (buf[4]<<8)|buf[5];
175 ancount = (buf[6]<<8)|buf[7];
177 p = buf+12;
178 p = skipquestion(buf, buf+n, p, qdcount);
179 p = unpack(buf, buf+n, p, &t, ancount);
180 USED(p);
181 return t;
184 static struct {
185 char *s;
186 int t;
187 } dnsnames[] =
189 "ip", Ta,
190 "ns", Tns,
191 "md", Tmd,
192 "mf", Tmf,
193 "cname", Tcname,
194 "soa", Tsoa,
195 "mb", Tmb,
196 "mg", Tmg,
197 "mr", Tmr,
198 "null", Tnull,
199 "ptr", Tptr,
200 "hinfo", Thinfo,
201 "minfo", Tminfo,
202 "mx", Tmx,
203 "txt", Ttxt,
204 "rp", Trp,
205 "key", Tkey,
206 "cert", Tcert,
207 "sig", Tsig,
208 "aaaa", Taaaa,
209 "ixfr", Tixfr,
210 "axfr", Taxfr,
211 "all", Call,
212 };
214 static char*
215 type2name(int t)
217 int i;
219 for(i=0; i<nelem(dnsnames); i++)
220 if(dnsnames[i].t == t)
221 return dnsnames[i].s;
222 return nil;
225 static int
226 name2type(char *name)
228 int i;
230 for(i=0; i<nelem(dnsnames); i++)
231 if(strcmp(name, dnsnames[i].s) == 0)
232 return dnsnames[i].t;
233 return -1;
236 static uchar*
237 skipquestion(uchar *buf, uchar *ebuf, uchar *p, int n)
239 int i, len;
240 char tmp[100];
242 for(i=0; i<n; i++){
243 if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) <= 0)
244 return nil;
245 p += 4+len;
247 return p;
250 static uchar*
251 unpack(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt, int n)
253 int i;
254 Ndbtuple *first, *last, *t;
256 *tt = nil;
257 first = nil;
258 last = nil;
259 for(i=0; i<n; i++){
260 if((p = rrnext(buf, ebuf, p, &t)) == nil){
261 if(first)
262 ndbfree(first);
263 return nil;
265 if(t == nil) /* unimplemented rr type */
266 continue;
267 if(last)
268 last->entry = t;
269 else
270 first = t;
271 for(last=t; last->entry; last=last->entry)
272 last->line = last->entry;
273 last->line = t;
275 *tt = first;
276 return p;
279 #define G2(p) nhgets(p)
280 #define G4(p) nhgetl(p)
282 static uchar*
283 rrnext(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt)
285 char tmp[Ndbvlen];
286 char b[MAXRR];
287 uchar ip[IPaddrlen];
288 int len;
289 Ndbtuple *first, *t;
290 int rrtype;
291 int rrlen;
293 first = nil;
294 t = nil;
295 *tt = nil;
296 if(p == nil)
297 return nil;
299 if((len = dn_expand(buf, ebuf, p, b, sizeof b)) < 0){
300 corrupt:
301 werrstr("corrupt dns packet");
302 if(first)
303 ndbfree(first);
304 return nil;
306 p += len;
308 rrtype = G2(p);
309 rrlen = G2(p+8);
310 p += 10;
312 if(rrtype == Tptr)
313 first = ndbnew("ptr", b);
314 else
315 first = ndbnew("dom", b);
317 switch(rrtype){
318 default:
319 goto end;
320 case Thinfo:
321 t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os");
322 break;
323 case Tminfo:
324 t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox");
325 break;
326 case Tmx:
327 t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx");
328 break;
329 case Tcname:
330 case Tmd:
331 case Tmf:
332 case Tmg:
333 case Tmr:
334 case Tmb:
335 case Tns:
336 case Tptr:
337 case Trp:
338 t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype));
339 break;
340 case Ta:
341 if(rrlen != IPv4addrlen)
342 goto corrupt;
343 memmove(ip, v4prefix, IPaddrlen);
344 memmove(ip+IPv4off, p, IPv4addrlen);
345 snprint(tmp, sizeof tmp, "%I", ip);
346 t = ndbnew("ip", tmp);
347 p += rrlen;
348 break;
349 case Taaaa:
350 if(rrlen != IPaddrlen)
351 goto corrupt;
352 snprint(tmp, sizeof tmp, "%I", ip);
353 t = ndbnew("ip", tmp);
354 p += rrlen;
355 break;
356 case Tnull:
357 snprint(tmp, sizeof tmp, "%.*H", rrlen, p);
358 t = ndbnew("null", tmp);
359 p += rrlen;
360 break;
361 case Ttxt:
362 t = rrunpack(buf, ebuf, &p, "Y", "txt");
363 break;
365 case Tsoa:
366 t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox",
367 "serial", "refresh", "retry", "expire", "ttl");
368 break;
370 case Tkey:
371 t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key");
372 break;
374 case Tsig:
375 t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels",
376 "ttl", "exp", "incep", "tag", "signer", "sig");
377 break;
379 case Tcert:
380 t = rrunpack(buf, ebuf, &p, "SSCY", "type", "tag", "alg", "cert");
381 break;
383 if(t == nil)
384 goto corrupt;
386 end:
387 first->entry = t;
388 *tt = first;
389 return p;
392 static Ndbtuple*
393 rrunpack(uchar *buf, uchar *ebuf, uchar **pp, char *fmt, ...)
395 char *name;
396 int len, n;
397 uchar *p;
398 va_list arg;
399 Ndbtuple *t, *first, *last;
400 char tmp[Ndbvlen];
402 p = *pp;
403 va_start(arg, fmt);
404 first = nil;
405 last = nil;
406 for(; *fmt; fmt++){
407 name = va_arg(arg, char*);
408 switch(*fmt){
409 default:
410 return nil;
411 case 'C':
412 snprint(tmp, sizeof tmp, "%d", *p++);
413 break;
414 case 'S':
415 snprint(tmp, sizeof tmp, "%d", G2(p));
416 p += 2;
417 break;
418 case 'L':
419 snprint(tmp, sizeof tmp, "%d", G4(p));
420 p += 4;
421 break;
422 case 'N':
423 if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) < 0)
424 return nil;
425 p += len;
426 break;
427 case 'Y':
428 len = *p++;
429 n = len;
430 if(n >= sizeof tmp)
431 n = sizeof tmp-1;
432 memmove(tmp, p, n);
433 p += len;
434 tmp[n] = 0;
435 break;
437 t = ndbnew(name, tmp);
438 if(last)
439 last->entry = t;
440 else
441 first = t;
442 last = t;
444 *pp = p;
445 return first;