URI:
       tconvM2DNS.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
       ---
       tconvM2DNS.c (7257B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <ip.h>
            4 #include <bio.h>
            5 #include <ndb.h>
            6 #include "dns.h"
            7 
            8 typedef struct Scan        Scan;
            9 struct Scan
           10 {
           11         uchar        *base;
           12         uchar        *p;
           13         uchar        *ep;
           14         char        *err;
           15 };
           16 
           17 #define NAME(x)                gname(x, sp)
           18 #define SYMBOL(x)        (x = gsym(sp))
           19 #define STRING(x)        (x = gstr(sp))
           20 #define USHORT(x)        (x = gshort(sp))
           21 #define ULONG(x)        (x = glong(sp))
           22 #define UCHAR(x)        (x = gchar(sp))
           23 #define V4ADDR(x)        (x = gv4addr(sp))
           24 #define V6ADDR(x)        (x = gv6addr(sp))
           25 #define BYTES(x, y)        (y = gbytes(sp, &x, len - (sp->p - data)))
           26 
           27 static char *toolong = "too long";
           28 
           29 /*
           30  *  get a ushort/ulong
           31  */
           32 static ushort
           33 gchar(Scan *sp)
           34 {
           35         ushort x;
           36 
           37         if(sp->err)
           38                 return 0;
           39         if(sp->ep - sp->p < 1){
           40                 sp->err = toolong;
           41                 return 0;
           42         }
           43         x = sp->p[0];
           44         sp->p += 1;
           45         return x;
           46 }
           47 static ushort
           48 gshort(Scan *sp)
           49 {
           50         ushort x;
           51 
           52         if(sp->err)
           53                 return 0;
           54         if(sp->ep - sp->p < 2){
           55                 sp->err = toolong;
           56                 return 0;
           57         }
           58         x = (sp->p[0]<<8) | sp->p[1];
           59         sp->p += 2;
           60         return x;
           61 }
           62 static ulong
           63 glong(Scan *sp)
           64 {
           65         ulong x;
           66 
           67         if(sp->err)
           68                 return 0;
           69         if(sp->ep - sp->p < 4){
           70                 sp->err = toolong;
           71                 return 0;
           72         }
           73         x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
           74         sp->p += 4;
           75         return x;
           76 }
           77 
           78 /*
           79  *  get an ip address
           80  */
           81 static DN*
           82 gv4addr(Scan *sp)
           83 {
           84         char addr[32];
           85 
           86         if(sp->err)
           87                 return 0;
           88         if(sp->ep - sp->p < 4){
           89                 sp->err = toolong;
           90                 return 0;
           91         }
           92         snprint(addr, sizeof(addr), "%V", sp->p);
           93         sp->p += 4;
           94 
           95         return dnlookup(addr, Cin, 1);
           96 }
           97 static DN*
           98 gv6addr(Scan *sp)
           99 {
          100         char addr[64];
          101 
          102         if(sp->err)
          103                 return 0;
          104         if(sp->ep - sp->p < IPaddrlen){
          105                 sp->err = toolong;
          106                 return 0;
          107         }
          108         snprint(addr, sizeof(addr), "%I", sp->p);
          109         sp->p += IPaddrlen;
          110 
          111         return dnlookup(addr, Cin, 1);
          112 }
          113 
          114 /*
          115  *  get a string.  make it an internal symbol.
          116  */
          117 static DN*
          118 gsym(Scan *sp)
          119 {
          120         int n;
          121         char sym[Strlen+1];
          122 
          123         if(sp->err)
          124                 return 0;
          125         n = *(sp->p++);
          126         if(sp->p+n > sp->ep){
          127                 sp->err = toolong;
          128                 return 0;
          129         }
          130 
          131         if(n > Strlen){
          132                 sp->err = "illegal string";
          133                 return 0;
          134         }
          135         strncpy(sym, (char*)sp->p, n);
          136         sym[n] = 0;
          137         sp->p += n;
          138 
          139         return dnlookup(sym, Csym, 1);
          140 }
          141 
          142 /*
          143  *  get a string.  don't make it an internal symbol.
          144  */
          145 static Txt*
          146 gstr(Scan *sp)
          147 {
          148         int n;
          149         char sym[Strlen+1];
          150         Txt *t;
          151 
          152         if(sp->err)
          153                 return 0;
          154         n = *(sp->p++);
          155         if(sp->p+n > sp->ep){
          156                 sp->err = toolong;
          157                 return 0;
          158         }
          159 
          160         if(n > Strlen){
          161                 sp->err = "illegal string";
          162                 return 0;
          163         }
          164         strncpy(sym, (char*)sp->p, n);
          165         sym[n] = 0;
          166         sp->p += n;
          167 
          168         t = emalloc(sizeof(*t));
          169         t->next = nil;
          170         t->p = estrdup(sym);
          171         return t;
          172 }
          173 
          174 /*
          175  *  get a sequence of bytes
          176  */
          177 static int
          178 gbytes(Scan *sp, uchar **p, int n)
          179 {
          180         if(sp->err)
          181                 return 0;
          182         if(sp->p+n > sp->ep || n < 0){
          183                 sp->err = toolong;
          184                 return 0;
          185         }
          186         *p = emalloc(n);
          187         memmove(*p, sp->p, n);
          188         sp->p += n;
          189 
          190         return n;
          191 }
          192 
          193 /*
          194  *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
          195  */
          196 static char*
          197 gname(char *to, Scan *sp)
          198 {
          199         int len, off;
          200         int pointer;
          201         int n;
          202         char *tostart;
          203         char *toend;
          204         uchar *p;
          205 
          206         tostart = to;
          207         if(sp->err)
          208                 goto err;
          209         pointer = 0;
          210         p = sp->p;
          211         toend = to + Domlen;
          212         for(len = 0; *p; len += pointer ? 0 : (n+1)){
          213                 if((*p & 0xc0) == 0xc0){
          214                         /* pointer to other spot in message */
          215                         if(pointer++ > 10){
          216                                 sp->err = "pointer loop";
          217                                 goto err;
          218                         }
          219                         off = ((p[0]<<8) + p[1]) & 0x3ff;
          220                         p = sp->base + off;
          221                         if(p >= sp->ep){
          222                                 sp->err = "bad pointer";
          223                                 goto err;
          224                         }
          225                         n = 0;
          226                         continue;
          227                 }
          228                 n = *p++;
          229                 if(len + n < Domlen - 1){
          230                         if(to + n > toend){
          231                                 sp->err = toolong;
          232                                 goto err;
          233                         }
          234                         memmove(to, p, n);
          235                         to += n;
          236                 }
          237                 p += n;
          238                 if(*p){
          239                         if(to >= toend){
          240                                 sp->err = toolong;
          241                                 goto err;
          242                         }
          243                         *to++ = '.';
          244                 }
          245         }
          246         *to = 0;
          247         if(pointer)
          248                 sp->p += len + 2;        /* + 2 for pointer */
          249         else
          250                 sp->p += len + 1;        /* + 1 for the null domain */
          251         return tostart;
          252 err:
          253         *tostart = 0;
          254         return tostart;
          255 }
          256 
          257 /*
          258  *  convert the next RR from a message
          259  */
          260 static RR*
          261 convM2RR(Scan *sp)
          262 {
          263         RR *rp;
          264         int type;
          265         int class;
          266         uchar *data;
          267         int len;
          268         char dname[Domlen+1];
          269         Txt *t, **l;
          270 
          271 retry:
          272         NAME(dname);
          273         USHORT(type);
          274         USHORT(class);
          275 
          276         rp = rralloc(type);
          277         rp->owner = dnlookup(dname, class, 1);
          278         rp->type = type;
          279 
          280         ULONG(rp->ttl);
          281         rp->ttl += now;
          282         USHORT(len);
          283         data = sp->p;
          284 
          285         if(sp->p + len > sp->ep)
          286                 sp->err = toolong;
          287         if(sp->err){
          288                 rrfree(rp);
          289                 return 0;
          290         }
          291 
          292         switch(type){
          293         default:
          294                 /* unknown type, just ignore it */
          295                 sp->p = data + len;
          296                 rrfree(rp);
          297                 goto retry;
          298         case Thinfo:
          299                 SYMBOL(rp->cpu);
          300                 SYMBOL(rp->os);
          301                 break;
          302         case Tcname:
          303         case Tmb:
          304         case Tmd:
          305         case Tmf:
          306         case Tns:
          307                 rp->host = dnlookup(NAME(dname), Cin, 1);
          308                 break;
          309         case Tmg:
          310         case Tmr:
          311                 rp->mb = dnlookup(NAME(dname), Cin, 1);
          312                 break;
          313         case Tminfo:
          314                 rp->rmb = dnlookup(NAME(dname), Cin, 1);
          315                 rp->mb = dnlookup(NAME(dname), Cin, 1);
          316                 break;
          317         case Tmx:
          318                 USHORT(rp->pref);
          319                 rp->host = dnlookup(NAME(dname), Cin, 1);
          320                 break;
          321         case Ta:
          322                 V4ADDR(rp->ip);
          323                 break;
          324         case Taaaa:
          325                 V6ADDR(rp->ip);
          326                 break;
          327         case Tptr:
          328                 rp->ptr = dnlookup(NAME(dname), Cin, 1);
          329                 break;
          330         case Tsoa:
          331                 rp->host = dnlookup(NAME(dname), Cin, 1);
          332                 rp->rmb = dnlookup(NAME(dname), Cin, 1);
          333                 ULONG(rp->soa->serial);
          334                 ULONG(rp->soa->refresh);
          335                 ULONG(rp->soa->retry);
          336                 ULONG(rp->soa->expire);
          337                 ULONG(rp->soa->minttl);
          338                 break;
          339         case Ttxt:
          340                 l = &rp->txt;
          341                 *l = nil;
          342                 while(sp->p-data < len){
          343                         STRING(t);
          344                         *l = t;
          345                         l = &t->next;
          346                 }
          347                 break;
          348         case Tnull:
          349                 BYTES(rp->null->data, rp->null->dlen);
          350                 break;
          351         case Trp:
          352                 rp->rmb = dnlookup(NAME(dname), Cin, 1);
          353                 rp->rp = dnlookup(NAME(dname), Cin, 1);
          354                 break;
          355         case Tkey:
          356                 USHORT(rp->key->flags);
          357                 UCHAR(rp->key->proto);
          358                 UCHAR(rp->key->alg);
          359                 BYTES(rp->key->data, rp->key->dlen);
          360                 break;
          361         case Tsig:
          362                 USHORT(rp->sig->type);
          363                 UCHAR(rp->sig->alg);
          364                 UCHAR(rp->sig->labels);
          365                 ULONG(rp->sig->ttl);
          366                 ULONG(rp->sig->exp);
          367                 ULONG(rp->sig->incep);
          368                 USHORT(rp->sig->tag);
          369                 rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
          370                 BYTES(rp->sig->data, rp->sig->dlen);
          371                 break;
          372         case Tcert:
          373                 USHORT(rp->cert->type);
          374                 USHORT(rp->cert->tag);
          375                 UCHAR(rp->cert->alg);
          376                 BYTES(rp->cert->data, rp->cert->dlen);
          377                 break;
          378         }
          379         if(sp->p - data != len)
          380                 sp->err = "bad RR len";
          381         return rp;
          382 }
          383 
          384 /*
          385  *  convert the next question from a message
          386  */
          387 static RR*
          388 convM2Q(Scan *sp)
          389 {
          390         char dname[Domlen+1];
          391         int type;
          392         int class;
          393         RR *rp;
          394 
          395         NAME(dname);
          396         USHORT(type);
          397         USHORT(class);
          398         if(sp->err)
          399                 return 0;
          400 
          401         rp = rralloc(type);
          402         rp->owner = dnlookup(dname, class, 1);
          403 
          404         return rp;
          405 }
          406 
          407 static RR*
          408 rrloop(Scan *sp, int count, int quest)
          409 {
          410         int i;
          411         RR *first, *rp, **l;
          412 
          413         if(sp->err)
          414                 return 0;
          415         l = &first;
          416         first = 0;
          417         for(i = 0; i < count; i++){
          418                 rp = quest ? convM2Q(sp) : convM2RR(sp);
          419                 if(rp == 0)
          420                         break;
          421                 if(sp->err){
          422                         rrfree(rp);
          423                         break;
          424                 }
          425                 *l = rp;
          426                 l = &rp->next;
          427         }
          428         return first;
          429 }
          430 
          431 /*
          432  *  convert the next DNS from a message stream
          433  */
          434 char*
          435 convM2DNS(uchar *buf, int len, DNSmsg *m)
          436 {
          437         Scan scan;
          438         Scan *sp;
          439         char *err;
          440 
          441         scan.base = buf;
          442         scan.p = buf;
          443         scan.ep = buf + len;
          444         scan.err = 0;
          445         sp = &scan;
          446         memset(m, 0, sizeof(DNSmsg));
          447         USHORT(m->id);
          448         USHORT(m->flags);
          449         USHORT(m->qdcount);
          450         USHORT(m->ancount);
          451         USHORT(m->nscount);
          452         USHORT(m->arcount);
          453         m->qd = rrloop(sp, m->qdcount, 1);
          454         m->an = rrloop(sp, m->ancount, 0);
          455         m->ns = rrloop(sp, m->nscount, 0);
          456         err = scan.err;                                /* live with bad ar's */
          457         m->ar = rrloop(sp, m->arcount, 0);
          458         return err;
          459 }