commit bc5d57712754818a2320a385afbf1c0c9558a4b3 from: rsc date: Fri Jan 27 05:32:04 2006 UTC dns commit - ee51985f90394959068f41aa42f898c9bb972f08 commit + bc5d57712754818a2320a385afbf1c0c9558a4b3 blob - a49cd5e01e43fdfbaa7eacd2143905f8d9c9cbc5 blob + b7c9ee96968fb95c0f8b8d76d17bbd2a1b353a07 --- src/libndb/mkfile +++ src/libndb/mkfile @@ -21,6 +21,7 @@ OFILES=\ ndbparse.$O\ ndbreorder.$O\ ndbsubstitute.$O\ + sysdnsquery.$O\ HFILES=\ $PLAN9/include/ndb.h\ @@ -28,5 +29,6 @@ HFILES=\ <$PLAN9/src/mksyslib -$O.out: testipinfo.$O - $LD $prereq +testdns: testdns.$O $LIBDIR/$LIB + $LD -o $target $prereq + blob - /dev/null blob + 1561c4dda633a655005be7a4a4a9722d7835dc76 (mode 644) --- /dev/null +++ src/libndb/sysdnsquery.c @@ -0,0 +1,409 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ndbhf.h" + +static void nstrcpy(char*, char*, int); +static void mkptrname(char*, char*, int); +static Ndbtuple *doquery(char*, char*); + +/* + * Run a DNS lookup for val/type on net. + */ +Ndbtuple* +dnsquery(char *net, char *val, char *type) +{ + static int init; + char rip[128]; + Ndbtuple *t; + + USED(net); + + if(!init){ + init = 1; + fmtinstall('I', eipfmt); + } + /* give up early on stupid questions - vwhois */ + if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0) + return nil; + + /* zero out the error string */ + werrstr(""); + + /* if this is a reverse lookup, first look up the domain name */ + if(strcmp(type, "ptr") == 0){ + mkptrname(val, rip, sizeof rip); + t = doquery(rip, "ptr"); + }else + t = doquery(val, type); + + return t; +} + +/* + * convert address into a reverse lookup address + */ +static void +mkptrname(char *ip, char *rip, int rlen) +{ + char buf[128]; + char *p, *np; + int len; + + if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){ + nstrcpy(rip, ip, rlen); + return; + } + + nstrcpy(buf, ip, sizeof buf); + for(p = buf; *p; p++) + ; + *p = '.'; + np = rip; + len = 0; + while(p >= buf){ + len++; + p--; + if(*p == '.'){ + memmove(np, p+1, len); + np += len; + len = 0; + } + } + memmove(np, p+1, len); + np += len; + strcpy(np, "in-addr.arpa"); +} + +static void +nstrcpy(char *to, char *from, int len) +{ + strncpy(to, from, len); + to[len-1] = 0; +} + +/* + * Disgusting, ugly interface to libresolv, + * which everyone seems to have. + */ +enum +{ + MAXRR = 100, + MAXDNS = 4096, +}; + +static int name2type(char*); +static uchar *skipquestion(uchar*, uchar*, uchar*, int); +static uchar *unpack(uchar*, uchar*, uchar*, Ndbtuple**, int); +static uchar *rrnext(uchar*, uchar*, uchar*, Ndbtuple**); +static Ndbtuple *rrunpack(uchar*, uchar*, uchar**, char*, ...); + +static Ndbtuple* +doquery(char *name, char *type) +{ + int n, nstype; + uchar *buf, *p; + HEADER *h; + Ndbtuple *t; + + if((nstype = name2type(type)) < 0){ + werrstr("unknown dns type %s", type); + return nil; + } + + buf = malloc(MAXDNS); + if(buf == nil) + return nil; + + if((n = res_search(name, ns_c_in, nstype, buf, MAXDNS)) < 0){ + free(buf); + return nil; + } + if(n >= MAXDNS){ + free(buf); + werrstr("too much dns information"); + return nil; + } + + h = (HEADER*)buf; + h->qdcount = ntohs(h->qdcount); + h->ancount = ntohs(h->ancount); + h->nscount = ntohs(h->nscount); + h->arcount = ntohs(h->arcount); + + p = buf+sizeof(HEADER); + p = skipquestion(buf, buf+n, p, h->qdcount); + p = unpack(buf, buf+n, p, &t, h->ancount); + USED(p); + return t; +} + +static struct { + char *s; + int t; +} dnsnames[] = +{ + "ip", ns_t_a, + "ns", ns_t_ns, + "md", ns_t_md, + "mf", ns_t_mf, + "cname", ns_t_cname, + "soa", ns_t_soa, + "mb", ns_t_mb, + "mg", ns_t_mg, + "mr", ns_t_mr, + "null", ns_t_null, + "ptr", ns_t_ptr, + "hinfo", ns_t_hinfo, + "minfo", ns_t_minfo, + "mx", ns_t_mx, + "txt", ns_t_txt, + "rp", ns_t_rp, + "key", ns_t_key, + "cert", ns_t_cert, + "sig", ns_t_sig, + "aaaa", ns_t_aaaa, + "ixfr", ns_t_ixfr, + "axfr", ns_t_axfr, + "all", ns_t_any, +}; + +static char* +type2name(int t) +{ + int i; + + for(i=0; ientry = t; + else + first = t; + for(last=t; last->entry; last=last->entry) + last->line = last->entry; + last->line = t; + } + *tt = first; + return p; +} + +#define G2(p) nhgets(p) +#define G4(p) nhgetl(p) + +static uchar* +rrnext(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt) +{ + char tmp[Ndbvlen]; + char b[MAXRR]; + uchar ip[IPaddrlen]; + int len; + Ndbtuple *first, *t; + int rrtype; + int rrlen; + + first = nil; + t = nil; + *tt = nil; + if(p == nil) + return nil; + + if((len = dn_expand(buf, ebuf, p, b, sizeof b)) < 0){ + corrupt: + werrstr("corrupt dns packet"); + if(first) + ndbfree(first); + return nil; + } + p += len; + + rrtype = G2(p); + rrlen = G2(p+8); + p += 10; + + if(rrtype == ns_t_ptr) + first = ndbnew("ptr", b); + else + first = ndbnew("dom", b); + + switch(rrtype){ + default: + goto end; + case ns_t_hinfo: + t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os"); + break; + case ns_t_minfo: + t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox"); + break; + case ns_t_mx: + t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx"); + break; + case ns_t_cname: + case ns_t_md: + case ns_t_mf: + case ns_t_mg: + case ns_t_mr: + case ns_t_mb: + case ns_t_ns: + case ns_t_ptr: + case ns_t_rp: + t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype)); + break; + case ns_t_a: + if(rrlen != IPv4addrlen) + goto corrupt; + memmove(ip, v4prefix, IPaddrlen); + memmove(ip+IPv4off, p, IPv4addrlen); + snprint(tmp, sizeof tmp, "%I", ip); + t = ndbnew("ip", tmp); + p += rrlen; + break; + case ns_t_aaaa: + if(rrlen != IPaddrlen) + goto corrupt; + snprint(tmp, sizeof tmp, "%I", ip); + t = ndbnew("ip", tmp); + p += rrlen; + break; + case ns_t_null: + snprint(tmp, sizeof tmp, "%.*H", rrlen, p); + t = ndbnew("null", tmp); + p += rrlen; + break; + case ns_t_txt: + t = rrunpack(buf, ebuf, &p, "Y", "txt"); + break; + + case ns_t_soa: + t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox", + "serial", "refresh", "retry", "expire", "ttl"); + break; + + case ns_t_key: + t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key"); + break; + + case ns_t_sig: + t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels", + "ttl", "exp", "incep", "tag", "signer", "sig"); + break; + + case ns_t_cert: + t = rrunpack(buf, ebuf, &p, "SSCY", "type", "tag", "alg", "cert"); + break; + } + if(t == nil) + goto corrupt; + +end: + first->entry = t; + *tt = first; + return p; +} + +static Ndbtuple* +rrunpack(uchar *buf, uchar *ebuf, uchar **pp, char *fmt, ...) +{ + char *name; + int len, n; + uchar *p; + va_list arg; + Ndbtuple *t, *first, *last; + char tmp[Ndbvlen]; + + p = *pp; + va_start(arg, fmt); + first = nil; + last = nil; + for(; *fmt; fmt++){ + name = va_arg(arg, char*); + switch(*fmt){ + default: + return nil; + case 'C': + snprint(tmp, sizeof tmp, "%d", *p++); + break; + case 'S': + snprint(tmp, sizeof tmp, "%d", G2(p)); + p += 2; + break; + case 'L': + snprint(tmp, sizeof tmp, "%d", G4(p)); + p += 4; + break; + case 'N': + if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) < 0) + return nil; + p += len; + break; + case 'Y': + len = *p++; + n = len; + if(n >= sizeof tmp) + n = sizeof tmp-1; + memmove(tmp, p, n); + p += len; + tmp[n] = 0; + break; + } + t = ndbnew(name, tmp); + if(last) + last->entry = t; + else + first = t; + last = t; + } + *pp = p; + return first; +} blob - /dev/null blob + 6c72c5d86fb95ba0de361327439366d16c90c83b (mode 644) --- /dev/null +++ src/libndb/testdns.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +void +main(int argc, char **argv) +{ + Ndbtuple *t, *t0; + + ARGBEGIN{ + default: + goto usage; + }ARGEND + + if(argc != 2){ + usage: + fprint(2, "usage: testdns name val\n"); + exits("usage"); + } + + quotefmtinstall(); + if((t = dnsquery(nil, argv[0], argv[1])) == nil) + sysfatal("dnsquery: %r"); + + for(t0=t; t; t=t->entry){ + print("%s=%q ", t->attr, t->val); + if(t->line == t0){ + print("\n"); + t0 = t->entry; + } + } + exits(0); +} +