#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, /* RR types */ Ta= 1, Tns= 2, Tmd= 3, Tmf= 4, Tcname= 5, Tsoa= 6, Tmb= 7, Tmg= 8, Tmr= 9, Tnull= 10, Twks= 11, Tptr= 12, Thinfo= 13, Tminfo= 14, Tmx= 15, Ttxt= 16, Trp= 17, Tsig= 24, Tkey= 25, Taaaa= 28, Tcert= 37, /* query types (all RR types are also queries) */ Tixfr= 251, /* incremental zone transfer */ Taxfr= 252, /* zone transfer */ Tmailb= 253, /* { Tmb, Tmg, Tmr } */ Tall= 255, /* all records */ /* classes */ Csym= 0, /* internal symbols */ Cin= 1, /* internet */ Ccs, /* CSNET (obsolete) */ Cch, /* Chaos net */ Chs, /* Hesiod (?) */ /* class queries (all class types are also queries) */ Call= 255, /* all classes */ }; 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; Ndbtuple *t; int qdcount, ancount; 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, Cin, nstype, buf, MAXDNS)) < 0){ free(buf); return nil; } if(n >= MAXDNS){ free(buf); werrstr("too much dns information"); return nil; } qdcount = (buf[4]<<8)|buf[5]; ancount = (buf[6]<<8)|buf[7]; p = buf+12; p = skipquestion(buf, buf+n, p, qdcount); p = unpack(buf, buf+n, p, &t, ancount); USED(p); return t; } static struct { char *s; int t; } dnsnames[] = { "ip", Ta, "ns", Tns, "md", Tmd, "mf", Tmf, "cname", Tcname, "soa", Tsoa, "mb", Tmb, "mg", Tmg, "mr", Tmr, "null", Tnull, "ptr", Tptr, "hinfo", Thinfo, "minfo", Tminfo, "mx", Tmx, "txt", Ttxt, "rp", Trp, "key", Tkey, "cert", Tcert, "sig", Tsig, "aaaa", Taaaa, "ixfr", Tixfr, "axfr", Taxfr, "all", Call, }; 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 == Tptr) first = ndbnew("ptr", b); else first = ndbnew("dom", b); switch(rrtype){ default: goto end; case Thinfo: t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os"); break; case Tminfo: t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox"); break; case Tmx: t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx"); break; case Tcname: case Tmd: case Tmf: case Tmg: case Tmr: case Tmb: case Tns: case Tptr: case Trp: t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype)); break; case Ta: 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 Taaaa: if(rrlen != IPaddrlen) goto corrupt; snprint(tmp, sizeof tmp, "%I", ip); t = ndbnew("ip", tmp); p += rrlen; break; case Tnull: snprint(tmp, sizeof tmp, "%.*H", rrlen, p); t = ndbnew("null", tmp); p += rrlen; break; case Ttxt: t = rrunpack(buf, ebuf, &p, "Y", "txt"); break; case Tsoa: t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox", "serial", "refresh", "retry", "expire", "ttl"); break; case Tkey: t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key"); break; case Tsig: t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels", "ttl", "exp", "incep", "tag", "signer", "sig"); break; case Tcert: 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; }