URI:
       tsysdnsquery.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tsysdnsquery.c (7661B)
       ---
            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"
           11 
           12 static void nstrcpy(char*, char*, int);
           13 static void mkptrname(char*, char*, int);
           14 static Ndbtuple *doquery(char*, char*);
           15 
           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;
           25 
           26         USED(net);
           27 
           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;
           35 
           36         /* zero out the error string */
           37         werrstr("");
           38 
           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);
           45 
           46         return t;
           47 }
           48 
           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;
           58 
           59         if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){
           60                 nstrcpy(rip, ip, rlen);
           61                 return;
           62         }
           63 
           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 }
           83 
           84 static void
           85 nstrcpy(char *to, char *from, int len)
           86 {
           87         strncpy(to, from, len-1);
           88         to[len-1] = 0;
           89 }
           90 
           91 /*
           92  * Disgusting, ugly interface to libresolv,
           93  * which everyone seems to have.
           94  */
           95 enum
           96 {
           97         MAXRR = 100,
           98         MAXDNS = 4096,
           99 
          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,
          122 
          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 */
          128 
          129         /* classes */
          130         Csym=        0,        /* internal symbols */
          131         Cin=        1,        /* internet */
          132         Ccs,                /* CSNET (obsolete) */
          133         Cch,                /* Chaos net */
          134         Chs,                /* Hesiod (?) */
          135 
          136         /* class queries (all class types are also queries) */
          137         Call=        255        /* all classes */
          138 };
          139 
          140 
          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*, ...);
          146 
          147 static Ndbtuple*
          148 doquery(char *name, char *type)
          149 {
          150         int n, nstype;
          151         uchar *buf, *p;
          152         Ndbtuple *t;
          153         int qdcount, ancount;
          154 
          155         if((nstype = name2type(type)) < 0){
          156                 werrstr("unknown dns type %s", type);
          157                 return nil;
          158         }
          159 
          160         buf = malloc(MAXDNS);
          161         if(buf == nil)
          162                 return nil;
          163 
          164         if((n = res_search(name, Cin, nstype, buf, MAXDNS)) < 0){
          165                 free(buf);
          166                 return nil;
          167         }
          168         if(n >= MAXDNS){
          169                 free(buf);
          170                 werrstr("too much dns information");
          171                 return nil;
          172         }
          173 
          174         qdcount = (buf[4]<<8)|buf[5];
          175         ancount = (buf[6]<<8)|buf[7];
          176 
          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;
          182 }
          183 
          184 static struct {
          185         char *s;
          186         int t;
          187 } dnsnames[] =
          188 {
          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 };
          213 
          214 static char*
          215 type2name(int t)
          216 {
          217         int i;
          218 
          219         for(i=0; i<nelem(dnsnames); i++)
          220                 if(dnsnames[i].t == t)
          221                         return dnsnames[i].s;
          222         return nil;
          223 }
          224 
          225 static int
          226 name2type(char *name)
          227 {
          228         int i;
          229 
          230         for(i=0; i<nelem(dnsnames); i++)
          231                 if(strcmp(name, dnsnames[i].s) == 0)
          232                         return dnsnames[i].t;
          233         return -1;
          234 }
          235 
          236 static uchar*
          237 skipquestion(uchar *buf, uchar *ebuf, uchar *p, int n)
          238 {
          239         int i, len;
          240         char tmp[100];
          241 
          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;
          246         }
          247         return p;
          248 }
          249 
          250 static uchar*
          251 unpack(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt, int n)
          252 {
          253         int i;
          254         Ndbtuple *first, *last, *t;
          255 
          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;
          264                 }
          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;
          274         }
          275         *tt = first;
          276         return p;
          277 }
          278 
          279 #define G2(p) nhgets(p)
          280 #define G4(p) nhgetl(p)
          281 
          282 static uchar*
          283 rrnext(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt)
          284 {
          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;
          292 
          293         first = nil;
          294         t = nil;
          295         *tt = nil;
          296         if(p == nil)
          297                 return nil;
          298 
          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;
          305         }
          306         p += len;
          307 
          308         rrtype = G2(p);
          309         rrlen = G2(p+8);
          310         p += 10;
          311 
          312         if(rrtype == Tptr)
          313                 first = ndbnew("ptr", b);
          314         else
          315                 first = ndbnew("dom", b);
          316 
          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;
          364 
          365         case Tsoa:
          366                 t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox",
          367                         "serial", "refresh", "retry", "expire", "ttl");
          368                 break;
          369 
          370         case Tkey:
          371                 t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key");
          372                 break;
          373 
          374         case Tsig:
          375                 t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels",
          376                         "ttl", "exp", "incep", "tag", "signer", "sig");
          377                 break;
          378 
          379         case Tcert:
          380                 t = rrunpack(buf, ebuf, &p, "SSCY", "type", "tag", "alg", "cert");
          381                 break;
          382         }
          383         if(t == nil)
          384                 goto corrupt;
          385 
          386 end:
          387         first->entry = t;
          388         *tt = first;
          389         return p;
          390 }
          391 
          392 static Ndbtuple*
          393 rrunpack(uchar *buf, uchar *ebuf, uchar **pp, char *fmt, ...)
          394 {
          395         char *name;
          396         int len, n;
          397         uchar *p;
          398         va_list arg;
          399         Ndbtuple *t, *first, *last;
          400         char tmp[Ndbvlen];
          401 
          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;
          436                 }
          437                 t = ndbnew(name, tmp);
          438                 if(last)
          439                         last->entry = t;
          440                 else
          441                         first = t;
          442                 last = t;
          443         }
          444         *pp = p;
          445         return first;
          446 }