13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <ip.h> 43e12c5d1SDavid du Colombier #include "dns.h" 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier typedef struct Scan Scan; 73e12c5d1SDavid du Colombier struct Scan 83e12c5d1SDavid du Colombier { 9*82f6abeeSDavid du Colombier uchar *base; /* input buffer */ 10*82f6abeeSDavid du Colombier uchar *p; /* current position */ 11*82f6abeeSDavid du Colombier uchar *ep; /* byte after the end */ 124f8f669cSDavid du Colombier 133e12c5d1SDavid du Colombier char *err; 144f8f669cSDavid du Colombier char errbuf[256]; /* hold a formatted error sometimes */ 154f8f669cSDavid du Colombier int rcode; /* outgoing response codes (reply flags) */ 1676783259SDavid du Colombier int stop; /* flag: stop processing */ 17a41547ffSDavid du Colombier int trunc; /* flag: input truncated */ 183e12c5d1SDavid du Colombier }; 193e12c5d1SDavid du Colombier 204f8f669cSDavid du Colombier static int 214f8f669cSDavid du Colombier errneg(RR *rp, Scan *sp, int actual) 224f8f669cSDavid du Colombier { 234f8f669cSDavid du Colombier snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R", 244f8f669cSDavid du Colombier actual, rp); 254f8f669cSDavid du Colombier sp->err = sp->errbuf; 264f8f669cSDavid du Colombier return 0; 274f8f669cSDavid du Colombier } 284f8f669cSDavid du Colombier 294f8f669cSDavid du Colombier static int 3076783259SDavid du Colombier errtoolong(RR *rp, Scan *sp, int remain, int need, char *where) 314f8f669cSDavid du Colombier { 324f8f669cSDavid du Colombier char *p, *ep; 334f8f669cSDavid du Colombier char ptype[64]; 344f8f669cSDavid du Colombier 354f8f669cSDavid du Colombier p = sp->errbuf; 364f8f669cSDavid du Colombier ep = sp->errbuf + sizeof sp->errbuf - 1; 374f8f669cSDavid du Colombier if (where) 384f8f669cSDavid du Colombier p = seprint(p, ep, "%s: ", where); 394f8f669cSDavid du Colombier if (rp) 404f8f669cSDavid du Colombier p = seprint(p, ep, "type %s RR: ", 414f8f669cSDavid du Colombier rrname(rp->type, ptype, sizeof ptype)); 4276783259SDavid du Colombier p = seprint(p, ep, "%d bytes needed; %d remain", need, remain); 434f8f669cSDavid du Colombier if (rp) 444f8f669cSDavid du Colombier seprint(p, ep, ": %R", rp); 454f8f669cSDavid du Colombier sp->err = sp->errbuf; 46a41547ffSDavid du Colombier /* hack to cope with servers that don't set Ftrunc when they should */ 47a41547ffSDavid du Colombier if (remain < Maxudp && need > Maxudp) 48a41547ffSDavid du Colombier sp->trunc = 1; 49*82f6abeeSDavid du Colombier if (debug && rp) 50b8b25780SDavid du Colombier dnslog("malformed rr: %R", rp); 514f8f669cSDavid du Colombier return 0; 524f8f669cSDavid du Colombier } 533e12c5d1SDavid du Colombier 543e12c5d1SDavid du Colombier /* 553e12c5d1SDavid du Colombier * get a ushort/ulong 563e12c5d1SDavid du Colombier */ 573e12c5d1SDavid du Colombier static ushort 584f8f669cSDavid du Colombier gchar(RR *rp, Scan *sp) 597dd7cddfSDavid du Colombier { 607dd7cddfSDavid du Colombier ushort x; 617dd7cddfSDavid du Colombier 627dd7cddfSDavid du Colombier if(sp->err) 637dd7cddfSDavid du Colombier return 0; 644f8f669cSDavid du Colombier if(sp->ep - sp->p < 1) 654f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar"); 667dd7cddfSDavid du Colombier x = sp->p[0]; 677dd7cddfSDavid du Colombier sp->p += 1; 687dd7cddfSDavid du Colombier return x; 697dd7cddfSDavid du Colombier } 707dd7cddfSDavid du Colombier static ushort 714f8f669cSDavid du Colombier gshort(RR *rp, Scan *sp) 723e12c5d1SDavid du Colombier { 733e12c5d1SDavid du Colombier ushort x; 743e12c5d1SDavid du Colombier 753e12c5d1SDavid du Colombier if(sp->err) 763e12c5d1SDavid du Colombier return 0; 774f8f669cSDavid du Colombier if(sp->ep - sp->p < 2) 784f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort"); 794f8f669cSDavid du Colombier x = sp->p[0]<<8 | sp->p[1]; 803e12c5d1SDavid du Colombier sp->p += 2; 813e12c5d1SDavid du Colombier return x; 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier static ulong 844f8f669cSDavid du Colombier glong(RR *rp, Scan *sp) 853e12c5d1SDavid du Colombier { 863e12c5d1SDavid du Colombier ulong x; 873e12c5d1SDavid du Colombier 883e12c5d1SDavid du Colombier if(sp->err) 893e12c5d1SDavid du Colombier return 0; 904f8f669cSDavid du Colombier if(sp->ep - sp->p < 4) 914f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong"); 924f8f669cSDavid du Colombier x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3]; 933e12c5d1SDavid du Colombier sp->p += 4; 943e12c5d1SDavid du Colombier return x; 953e12c5d1SDavid du Colombier } 963e12c5d1SDavid du Colombier 973e12c5d1SDavid du Colombier /* 983e12c5d1SDavid du Colombier * get an ip address 993e12c5d1SDavid du Colombier */ 1003e12c5d1SDavid du Colombier static DN* 1014f8f669cSDavid du Colombier gv4addr(RR *rp, Scan *sp) 1023e12c5d1SDavid du Colombier { 1033e12c5d1SDavid du Colombier char addr[32]; 1043e12c5d1SDavid du Colombier 1053e12c5d1SDavid du Colombier if(sp->err) 1063e12c5d1SDavid du Colombier return 0; 1074f8f669cSDavid du Colombier if(sp->ep - sp->p < 4) 1084f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr"); 1094f8f669cSDavid du Colombier snprint(addr, sizeof addr, "%V", sp->p); 1103e12c5d1SDavid du Colombier sp->p += 4; 1113e12c5d1SDavid du Colombier 1123e12c5d1SDavid du Colombier return dnlookup(addr, Cin, 1); 1133e12c5d1SDavid du Colombier } 1145d459b5aSDavid du Colombier static DN* 1154f8f669cSDavid du Colombier gv6addr(RR *rp, Scan *sp) 1165d459b5aSDavid du Colombier { 1175d459b5aSDavid du Colombier char addr[64]; 1185d459b5aSDavid du Colombier 1195d459b5aSDavid du Colombier if(sp->err) 1205d459b5aSDavid du Colombier return 0; 1214f8f669cSDavid du Colombier if(sp->ep - sp->p < IPaddrlen) 1224f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen, 1234f8f669cSDavid du Colombier "gv6addr"); 1244f8f669cSDavid du Colombier snprint(addr, sizeof addr, "%I", sp->p); 1255d459b5aSDavid du Colombier sp->p += IPaddrlen; 1265d459b5aSDavid du Colombier 1275d459b5aSDavid du Colombier return dnlookup(addr, Cin, 1); 1285d459b5aSDavid du Colombier } 1293e12c5d1SDavid du Colombier 1303e12c5d1SDavid du Colombier /* 1313e12c5d1SDavid du Colombier * get a string. make it an internal symbol. 1323e12c5d1SDavid du Colombier */ 1333e12c5d1SDavid du Colombier static DN* 1344f8f669cSDavid du Colombier gsym(RR *rp, Scan *sp) 1353e12c5d1SDavid du Colombier { 1363e12c5d1SDavid du Colombier int n; 1373e12c5d1SDavid du Colombier char sym[Strlen+1]; 1383e12c5d1SDavid du Colombier 1393e12c5d1SDavid du Colombier if(sp->err) 1403e12c5d1SDavid du Colombier return 0; 1414f8f669cSDavid du Colombier n = 0; 1424f8f669cSDavid du Colombier if (sp->p < sp->ep) 1433e12c5d1SDavid du Colombier n = *(sp->p++); 1444f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 1454f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym"); 1463e12c5d1SDavid du Colombier 1473e12c5d1SDavid du Colombier if(n > Strlen){ 1484f8f669cSDavid du Colombier sp->err = "illegal string (symbol)"; 1493e12c5d1SDavid du Colombier return 0; 1503e12c5d1SDavid du Colombier } 1513e12c5d1SDavid du Colombier strncpy(sym, (char*)sp->p, n); 1523e12c5d1SDavid du Colombier sym[n] = 0; 1534f8f669cSDavid du Colombier if (strlen(sym) != n) 1544f8f669cSDavid du Colombier sp->err = "symbol shorter than declared length"; 1553e12c5d1SDavid du Colombier sp->p += n; 1563e12c5d1SDavid du Colombier 1573e12c5d1SDavid du Colombier return dnlookup(sym, Csym, 1); 1583e12c5d1SDavid du Colombier } 1593e12c5d1SDavid du Colombier 1603e12c5d1SDavid du Colombier /* 16160845620SDavid du Colombier * get a string. don't make it an internal symbol. 16260845620SDavid du Colombier */ 16360845620SDavid du Colombier static Txt* 1644f8f669cSDavid du Colombier gstr(RR *rp, Scan *sp) 16560845620SDavid du Colombier { 16660845620SDavid du Colombier int n; 16760845620SDavid du Colombier char sym[Strlen+1]; 16860845620SDavid du Colombier Txt *t; 16960845620SDavid du Colombier 17060845620SDavid du Colombier if(sp->err) 17160845620SDavid du Colombier return 0; 1724f8f669cSDavid du Colombier n = 0; 1734f8f669cSDavid du Colombier if (sp->p < sp->ep) 17460845620SDavid du Colombier n = *(sp->p++); 1754f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 1764f8f669cSDavid du Colombier return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr"); 17760845620SDavid du Colombier 17860845620SDavid du Colombier if(n > Strlen){ 17960845620SDavid du Colombier sp->err = "illegal string"; 18060845620SDavid du Colombier return 0; 18160845620SDavid du Colombier } 18260845620SDavid du Colombier strncpy(sym, (char*)sp->p, n); 18360845620SDavid du Colombier sym[n] = 0; 1844f8f669cSDavid du Colombier if (strlen(sym) != n) 1854f8f669cSDavid du Colombier sp->err = "string shorter than declared length"; 18660845620SDavid du Colombier sp->p += n; 18760845620SDavid du Colombier 18860845620SDavid du Colombier t = emalloc(sizeof(*t)); 18960845620SDavid du Colombier t->next = nil; 19060845620SDavid du Colombier t->p = estrdup(sym); 19160845620SDavid du Colombier return t; 19260845620SDavid du Colombier } 19360845620SDavid du Colombier 19460845620SDavid du Colombier /* 1957dd7cddfSDavid du Colombier * get a sequence of bytes 1967dd7cddfSDavid du Colombier */ 1977dd7cddfSDavid du Colombier static int 1984f8f669cSDavid du Colombier gbytes(RR *rp, Scan *sp, uchar **p, int n) 1997dd7cddfSDavid du Colombier { 2004f8f669cSDavid du Colombier *p = nil; /* i think this is a good idea */ 2017dd7cddfSDavid du Colombier if(sp->err) 2027dd7cddfSDavid du Colombier return 0; 2034f8f669cSDavid du Colombier if(n < 0) 2044f8f669cSDavid du Colombier return errneg(rp, sp, n); 2054f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 2064f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes"); 2079a747e4fSDavid du Colombier *p = emalloc(n); 2087dd7cddfSDavid du Colombier memmove(*p, sp->p, n); 2097dd7cddfSDavid du Colombier sp->p += n; 2107dd7cddfSDavid du Colombier 2117dd7cddfSDavid du Colombier return n; 2127dd7cddfSDavid du Colombier } 2137dd7cddfSDavid du Colombier 2147dd7cddfSDavid du Colombier /* 2153e12c5d1SDavid du Colombier * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 2163e12c5d1SDavid du Colombier */ 2173e12c5d1SDavid du Colombier static char* 2184f8f669cSDavid du Colombier gname(char *to, RR *rp, Scan *sp) 2193e12c5d1SDavid du Colombier { 2204f8f669cSDavid du Colombier int len, off, pointer, n; 2214f8f669cSDavid du Colombier char *tostart, *toend; 2223e12c5d1SDavid du Colombier uchar *p; 2233e12c5d1SDavid du Colombier 2243e12c5d1SDavid du Colombier tostart = to; 22576783259SDavid du Colombier if(sp->err || sp->stop) 2263e12c5d1SDavid du Colombier goto err; 2273e12c5d1SDavid du Colombier pointer = 0; 2283e12c5d1SDavid du Colombier p = sp->p; 229*82f6abeeSDavid du Colombier if (p == nil) { 230*82f6abeeSDavid du Colombier dnslog("gname: %R: nil sp->p", rp); 231*82f6abeeSDavid du Colombier goto err; 232*82f6abeeSDavid du Colombier } 2333e12c5d1SDavid du Colombier toend = to + Domlen; 23476783259SDavid du Colombier for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) { 23576783259SDavid du Colombier n = 0; 23676783259SDavid du Colombier switch (*p & 0300) { 23776783259SDavid du Colombier case 0: /* normal label */ 23876783259SDavid du Colombier if (p < sp->ep) 23976783259SDavid du Colombier n = *p++ & 077; /* pick up length */ 24076783259SDavid du Colombier if(len + n < Domlen - 1){ 24176783259SDavid du Colombier if(n > toend - to){ 24276783259SDavid du Colombier errtoolong(rp, sp, toend - to, n, 24376783259SDavid du Colombier "name too long"); 24476783259SDavid du Colombier goto err; 24576783259SDavid du Colombier } 24676783259SDavid du Colombier memmove(to, p, n); 24776783259SDavid du Colombier to += n; 24876783259SDavid du Colombier } 24976783259SDavid du Colombier p += n; 25076783259SDavid du Colombier if(*p){ 25176783259SDavid du Colombier if(to >= toend){ 25276783259SDavid du Colombier errtoolong(rp, sp, toend - to, 2, 25376783259SDavid du Colombier "more name components but no bytes left"); 25476783259SDavid du Colombier goto err; 25576783259SDavid du Colombier } 25676783259SDavid du Colombier *to++ = '.'; 25776783259SDavid du Colombier } 25876783259SDavid du Colombier break; 25976783259SDavid du Colombier case 0100: /* edns extended label type, rfc 2671 */ 26076783259SDavid du Colombier /* 26176783259SDavid du Colombier * treat it like an EOF for now; it seems to be at 26276783259SDavid du Colombier * the end of a long tcp reply. 26376783259SDavid du Colombier */ 2645d34ce99SDavid du Colombier dnslog("edns label; first byte 0%o = '%c'", *p, *p); 26576783259SDavid du Colombier sp->stop = 1; 26676783259SDavid du Colombier goto err; 26776783259SDavid du Colombier case 0200: /* reserved */ 26876783259SDavid du Colombier sp->err = "reserved-use label present"; 26976783259SDavid du Colombier goto err; 27076783259SDavid du Colombier case 0300: /* pointer to other spot in message */ 2713e12c5d1SDavid du Colombier if(pointer++ > 10){ 2723e12c5d1SDavid du Colombier sp->err = "pointer loop"; 2733e12c5d1SDavid du Colombier goto err; 2743e12c5d1SDavid du Colombier } 2755d34ce99SDavid du Colombier off = (p[0] & 077)<<8 | p[1]; 2763e12c5d1SDavid du Colombier p = sp->base + off; 2773e12c5d1SDavid du Colombier if(p >= sp->ep){ 2783e12c5d1SDavid du Colombier sp->err = "bad pointer"; 2793e12c5d1SDavid du Colombier goto err; 2803e12c5d1SDavid du Colombier } 2813e12c5d1SDavid du Colombier n = 0; 28276783259SDavid du Colombier break; 2833e12c5d1SDavid du Colombier } 2843e12c5d1SDavid du Colombier } 2853e12c5d1SDavid du Colombier *to = 0; 2863e12c5d1SDavid du Colombier if(pointer) 2873e12c5d1SDavid du Colombier sp->p += len + 2; /* + 2 for pointer */ 2883e12c5d1SDavid du Colombier else 2893e12c5d1SDavid du Colombier sp->p += len + 1; /* + 1 for the null domain */ 2903e12c5d1SDavid du Colombier return tostart; 2913e12c5d1SDavid du Colombier err: 2923e12c5d1SDavid du Colombier *tostart = 0; 2933e12c5d1SDavid du Colombier return tostart; 2943e12c5d1SDavid du Colombier } 2953e12c5d1SDavid du Colombier 2963e12c5d1SDavid du Colombier /* 2974f8f669cSDavid du Colombier * ms windows 2000 seems to get the bytes backward in the type field 2984f8f669cSDavid du Colombier * of ptr records, so return a format error as feedback. 2994f8f669cSDavid du Colombier */ 300d9924332SDavid du Colombier static ushort 301d9924332SDavid du Colombier mstypehack(Scan *sp, ushort type, char *where) 3024f8f669cSDavid du Colombier { 303d9924332SDavid du Colombier if ((uchar)type == 0 && (type>>8) != 0) { 3044f8f669cSDavid du Colombier USED(where); 3054f8f669cSDavid du Colombier // dnslog("%s: byte-swapped type field in ptr rr from win2k", 3064f8f669cSDavid du Colombier // where); 307d9924332SDavid du Colombier if (sp->rcode == Rok) 3084f8f669cSDavid du Colombier sp->rcode = Rformat; 309*82f6abeeSDavid du Colombier type >>= 8; 3104f8f669cSDavid du Colombier } 311d9924332SDavid du Colombier return type; 3124f8f669cSDavid du Colombier } 3134f8f669cSDavid du Colombier 314*82f6abeeSDavid du Colombier #define NAME(x) gname(x, rp, sp) 315*82f6abeeSDavid du Colombier #define SYMBOL(x) ((x) = gsym(rp, sp)) 316*82f6abeeSDavid du Colombier #define STRING(x) ((x) = gstr(rp, sp)) 317*82f6abeeSDavid du Colombier #define USHORT(x) ((x) = gshort(rp, sp)) 318*82f6abeeSDavid du Colombier #define ULONG(x) ((x) = glong(rp, sp)) 319*82f6abeeSDavid du Colombier #define UCHAR(x) ((x) = gchar(rp, sp)) 320*82f6abeeSDavid du Colombier #define V4ADDR(x) ((x) = gv4addr(rp, sp)) 321*82f6abeeSDavid du Colombier #define V6ADDR(x) ((x) = gv6addr(rp, sp)) 322*82f6abeeSDavid du Colombier #define BYTES(x, y) ((y) = gbytes(rp, sp, &(x), len - (sp->p - data))) 323*82f6abeeSDavid du Colombier 3244f8f669cSDavid du Colombier /* 3253e12c5d1SDavid du Colombier * convert the next RR from a message 3263e12c5d1SDavid du Colombier */ 3273e12c5d1SDavid du Colombier static RR* 3284f8f669cSDavid du Colombier convM2RR(Scan *sp, char *what) 3293e12c5d1SDavid du Colombier { 330*82f6abeeSDavid du Colombier int type, class, len, left; 3313e12c5d1SDavid du Colombier char dname[Domlen+1]; 3324f8f669cSDavid du Colombier uchar *data; 333*82f6abeeSDavid du Colombier RR *rp; 33460845620SDavid du Colombier Txt *t, **l; 3353e12c5d1SDavid du Colombier 3367dd7cddfSDavid du Colombier retry: 337*82f6abeeSDavid du Colombier rp = nil; 3383e12c5d1SDavid du Colombier NAME(dname); 3393e12c5d1SDavid du Colombier USHORT(type); 3403e12c5d1SDavid du Colombier USHORT(class); 3413e12c5d1SDavid du Colombier 342d9924332SDavid du Colombier type = mstypehack(sp, type, "convM2RR"); 3433e12c5d1SDavid du Colombier rp = rralloc(type); 3443e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 3453e12c5d1SDavid du Colombier rp->type = type; 3463e12c5d1SDavid du Colombier 3473e12c5d1SDavid du Colombier ULONG(rp->ttl); 3487dd7cddfSDavid du Colombier rp->ttl += now; 349*82f6abeeSDavid du Colombier USHORT(len); /* length of data following */ 3503e12c5d1SDavid du Colombier data = sp->p; 351*82f6abeeSDavid du Colombier assert(data != nil); 352*82f6abeeSDavid du Colombier left = sp->ep - sp->p; 3537dd7cddfSDavid du Colombier 3544f8f669cSDavid du Colombier /* 3554f8f669cSDavid du Colombier * ms windows generates a lot of badly-formatted hints. 3564f8f669cSDavid du Colombier * hints are only advisory, so don't log complaints about them. 3574f8f669cSDavid du Colombier * it also generates answers in which p overshoots ep by exactly 3584f8f669cSDavid du Colombier * one byte; this seems to be harmless, so don't log them either. 3594f8f669cSDavid du Colombier */ 360*82f6abeeSDavid du Colombier if (len > left && 3614f8f669cSDavid du Colombier !(strcmp(what, "hints") == 0 || 36276783259SDavid du Colombier sp->p == sp->ep + 1 && strcmp(what, "answers") == 0)) 363*82f6abeeSDavid du Colombier errtoolong(rp, sp, left, len, "convM2RR"); 36476783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop){ 3657dd7cddfSDavid du Colombier rrfree(rp); 3665d34ce99SDavid du Colombier return nil; 3677dd7cddfSDavid du Colombier } 368*82f6abeeSDavid du Colombier /* even if we don't log an error message, truncate length to fit data */ 369*82f6abeeSDavid du Colombier if (len > left) 370*82f6abeeSDavid du Colombier len = left; 3717dd7cddfSDavid du Colombier 3723e12c5d1SDavid du Colombier switch(type){ 3737dd7cddfSDavid du Colombier default: 3747dd7cddfSDavid du Colombier /* unknown type, just ignore it */ 3757dd7cddfSDavid du Colombier sp->p = data + len; 3767dd7cddfSDavid du Colombier rrfree(rp); 3777dd7cddfSDavid du Colombier goto retry; 3783e12c5d1SDavid du Colombier case Thinfo: 37960845620SDavid du Colombier SYMBOL(rp->cpu); 38060845620SDavid du Colombier SYMBOL(rp->os); 3813e12c5d1SDavid du Colombier break; 3823e12c5d1SDavid du Colombier case Tcname: 3833e12c5d1SDavid du Colombier case Tmb: 3843e12c5d1SDavid du Colombier case Tmd: 3853e12c5d1SDavid du Colombier case Tmf: 3863e12c5d1SDavid du Colombier case Tns: 3873e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 3883e12c5d1SDavid du Colombier break; 3893e12c5d1SDavid du Colombier case Tmg: 3903e12c5d1SDavid du Colombier case Tmr: 3913e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 3923e12c5d1SDavid du Colombier break; 3933e12c5d1SDavid du Colombier case Tminfo: 3943e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 3953e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 3963e12c5d1SDavid du Colombier break; 3973e12c5d1SDavid du Colombier case Tmx: 3983e12c5d1SDavid du Colombier USHORT(rp->pref); 3993e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 4003e12c5d1SDavid du Colombier break; 4013e12c5d1SDavid du Colombier case Ta: 4025d459b5aSDavid du Colombier V4ADDR(rp->ip); 4035d459b5aSDavid du Colombier break; 4045d459b5aSDavid du Colombier case Taaaa: 4055d459b5aSDavid du Colombier V6ADDR(rp->ip); 4063e12c5d1SDavid du Colombier break; 4073e12c5d1SDavid du Colombier case Tptr: 4083e12c5d1SDavid du Colombier rp->ptr = dnlookup(NAME(dname), Cin, 1); 4093e12c5d1SDavid du Colombier break; 4103e12c5d1SDavid du Colombier case Tsoa: 4113e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 4123e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 4133e12c5d1SDavid du Colombier ULONG(rp->soa->serial); 4143e12c5d1SDavid du Colombier ULONG(rp->soa->refresh); 4153e12c5d1SDavid du Colombier ULONG(rp->soa->retry); 4163e12c5d1SDavid du Colombier ULONG(rp->soa->expire); 4173e12c5d1SDavid du Colombier ULONG(rp->soa->minttl); 4183e12c5d1SDavid du Colombier break; 4194f8f669cSDavid du Colombier case Tsrv: 4204f8f669cSDavid du Colombier USHORT(rp->srv->pri); 4214f8f669cSDavid du Colombier USHORT(rp->srv->weight); 422225077b0SDavid du Colombier USHORT(rp->port); 423225077b0SDavid du Colombier /* 424225077b0SDavid du Colombier * rfc2782 sez no name compression but to be 425225077b0SDavid du Colombier * backward-compatible with rfc2052, we try to expand the name. 426225077b0SDavid du Colombier * if the length is under 64 bytes, either interpretation is 427225077b0SDavid du Colombier * fine; if it's longer, we'll assume it's compressed, 428225077b0SDavid du Colombier * as recommended by rfc3597. 429225077b0SDavid du Colombier */ 430225077b0SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 4314f8f669cSDavid du Colombier break; 4327dd7cddfSDavid du Colombier case Ttxt: 43360845620SDavid du Colombier l = &rp->txt; 43460845620SDavid du Colombier *l = nil; 43560845620SDavid du Colombier while(sp->p - data < len){ 43660845620SDavid du Colombier STRING(t); 43760845620SDavid du Colombier *l = t; 43860845620SDavid du Colombier l = &t->next; 43960845620SDavid du Colombier } 4407dd7cddfSDavid du Colombier break; 4419a747e4fSDavid du Colombier case Tnull: 4429a747e4fSDavid du Colombier BYTES(rp->null->data, rp->null->dlen); 4439a747e4fSDavid du Colombier break; 4447dd7cddfSDavid du Colombier case Trp: 4457dd7cddfSDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 44660845620SDavid du Colombier rp->rp = dnlookup(NAME(dname), Cin, 1); 4477dd7cddfSDavid du Colombier break; 4487dd7cddfSDavid du Colombier case Tkey: 4497dd7cddfSDavid du Colombier USHORT(rp->key->flags); 4507dd7cddfSDavid du Colombier UCHAR(rp->key->proto); 4517dd7cddfSDavid du Colombier UCHAR(rp->key->alg); 4527dd7cddfSDavid du Colombier BYTES(rp->key->data, rp->key->dlen); 4537dd7cddfSDavid du Colombier break; 4547dd7cddfSDavid du Colombier case Tsig: 4557dd7cddfSDavid du Colombier USHORT(rp->sig->type); 4567dd7cddfSDavid du Colombier UCHAR(rp->sig->alg); 4577dd7cddfSDavid du Colombier UCHAR(rp->sig->labels); 4587dd7cddfSDavid du Colombier ULONG(rp->sig->ttl); 4597dd7cddfSDavid du Colombier ULONG(rp->sig->exp); 4607dd7cddfSDavid du Colombier ULONG(rp->sig->incep); 4617dd7cddfSDavid du Colombier USHORT(rp->sig->tag); 4627dd7cddfSDavid du Colombier rp->sig->signer = dnlookup(NAME(dname), Cin, 1); 4637dd7cddfSDavid du Colombier BYTES(rp->sig->data, rp->sig->dlen); 4647dd7cddfSDavid du Colombier break; 4657dd7cddfSDavid du Colombier case Tcert: 4667dd7cddfSDavid du Colombier USHORT(rp->cert->type); 4677dd7cddfSDavid du Colombier USHORT(rp->cert->tag); 4687dd7cddfSDavid du Colombier UCHAR(rp->cert->alg); 4697dd7cddfSDavid du Colombier BYTES(rp->cert->data, rp->cert->dlen); 4707dd7cddfSDavid du Colombier break; 4713e12c5d1SDavid du Colombier } 4724f8f669cSDavid du Colombier if(sp->p - data != len) { 4734f8f669cSDavid du Colombier char ptype[64]; 4744f8f669cSDavid du Colombier 4754f8f669cSDavid du Colombier /* 4764f8f669cSDavid du Colombier * ms windows 2000 generates cname queries for reverse lookups 4774f8f669cSDavid du Colombier * with this particular error. don't bother logging it. 4784f8f669cSDavid du Colombier * 4794f8f669cSDavid du Colombier * server: input error: bad cname RR len (actual 2 != len 0): 4804f8f669cSDavid du Colombier * 235.9.104.135.in-addr.arpa cname 4814f8f669cSDavid du Colombier * 235.9.104.135.in-addr.arpa from 135.104.9.235 4824f8f669cSDavid du Colombier */ 483b8b25780SDavid du Colombier if (type == Tcname && sp->p - data == 2 && len == 0) 4844f8f669cSDavid du Colombier return rp; 485225077b0SDavid du Colombier if (len > sp->p - data){ 48676783259SDavid du Colombier dnslog("bad %s RR len (%d bytes nominal, %lud actual): %R", 48776783259SDavid du Colombier rrname(type, ptype, sizeof ptype), len, 48876783259SDavid du Colombier sp->p - data, rp); 489225077b0SDavid du Colombier rrfree(rp); 490225077b0SDavid du Colombier rp = nil; 49176783259SDavid du Colombier } 492225077b0SDavid du Colombier } 493225077b0SDavid du Colombier // if(rp) dnslog("convM2RR: got %R", rp); 4943e12c5d1SDavid du Colombier return rp; 4953e12c5d1SDavid du Colombier } 4963e12c5d1SDavid du Colombier 4973e12c5d1SDavid du Colombier /* 4983e12c5d1SDavid du Colombier * convert the next question from a message 4993e12c5d1SDavid du Colombier */ 5003e12c5d1SDavid du Colombier static RR* 5013e12c5d1SDavid du Colombier convM2Q(Scan *sp) 5023e12c5d1SDavid du Colombier { 5033e12c5d1SDavid du Colombier char dname[Domlen+1]; 5044f8f669cSDavid du Colombier int type, class; 505*82f6abeeSDavid du Colombier RR *rp; 5063e12c5d1SDavid du Colombier 507*82f6abeeSDavid du Colombier rp = nil; 5083e12c5d1SDavid du Colombier NAME(dname); 5093e12c5d1SDavid du Colombier USHORT(type); 5103e12c5d1SDavid du Colombier USHORT(class); 51176783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop) 5124f8f669cSDavid du Colombier return nil; 5133e12c5d1SDavid du Colombier 514d9924332SDavid du Colombier type = mstypehack(sp, type, "convM2Q"); 5153e12c5d1SDavid du Colombier rp = rralloc(type); 5163e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 5173e12c5d1SDavid du Colombier 5183e12c5d1SDavid du Colombier return rp; 5193e12c5d1SDavid du Colombier } 5203e12c5d1SDavid du Colombier 5213e12c5d1SDavid du Colombier static RR* 5224f8f669cSDavid du Colombier rrloop(Scan *sp, char *what, int count, int quest) 5233e12c5d1SDavid du Colombier { 5243e12c5d1SDavid du Colombier int i; 5253e12c5d1SDavid du Colombier RR *first, *rp, **l; 5263e12c5d1SDavid du Colombier 52776783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop) 5284f8f669cSDavid du Colombier return nil; 5293e12c5d1SDavid du Colombier l = &first; 5304f8f669cSDavid du Colombier first = nil; 5313e12c5d1SDavid du Colombier for(i = 0; i < count; i++){ 5324f8f669cSDavid du Colombier rp = quest? convM2Q(sp): convM2RR(sp, what); 5334f8f669cSDavid du Colombier if(rp == nil) 534bd389b36SDavid du Colombier break; 5355d34ce99SDavid du Colombier setmalloctag(rp, getcallerpc(&sp)); 536b8b25780SDavid du Colombier /* 537b8b25780SDavid du Colombier * it might be better to ignore the bad rr, possibly break out, 538b8b25780SDavid du Colombier * but return the previous rrs, if any. that way our callers 539b8b25780SDavid du Colombier * would know that they had got a response, however ill-formed. 540b8b25780SDavid du Colombier */ 54176783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop){ 5423e12c5d1SDavid du Colombier rrfree(rp); 5433e12c5d1SDavid du Colombier break; 5443e12c5d1SDavid du Colombier } 5453e12c5d1SDavid du Colombier *l = rp; 5463e12c5d1SDavid du Colombier l = &rp->next; 5473e12c5d1SDavid du Colombier } 548*82f6abeeSDavid du Colombier // if(first) 5495d34ce99SDavid du Colombier // setmalloctag(first, getcallerpc(&sp)); 5503e12c5d1SDavid du Colombier return first; 5513e12c5d1SDavid du Colombier } 5523e12c5d1SDavid du Colombier 5533e12c5d1SDavid du Colombier /* 5544f8f669cSDavid du Colombier * convert the next DNS from a message stream. 5554f8f669cSDavid du Colombier * if there are formatting errors or the like during parsing of the message, 5564f8f669cSDavid du Colombier * set *codep to the outgoing response code (e.g., Rformat), which will 5574f8f669cSDavid du Colombier * abort processing and reply immediately with the outgoing response code. 5583e12c5d1SDavid du Colombier */ 5593e12c5d1SDavid du Colombier char* 5604f8f669cSDavid du Colombier convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep) 5613e12c5d1SDavid du Colombier { 562186d659cSDavid du Colombier char *err = nil; 5634f8f669cSDavid du Colombier RR *rp = nil; 5640319257bSDavid du Colombier Scan scan; 5650319257bSDavid du Colombier Scan *sp; 5663e12c5d1SDavid du Colombier 5674f8f669cSDavid du Colombier assert(len >= 0); 568*82f6abeeSDavid du Colombier assert(buf != nil); 5693e12c5d1SDavid du Colombier sp = &scan; 5700319257bSDavid du Colombier memset(sp, 0, sizeof *sp); 5710319257bSDavid du Colombier sp->base = sp->p = buf; 5720319257bSDavid du Colombier sp->ep = buf + len; 5730319257bSDavid du Colombier sp->err = nil; 5740319257bSDavid du Colombier sp->errbuf[0] = '\0'; 575*82f6abeeSDavid du Colombier sp->rcode = Rok; 5764f8f669cSDavid du Colombier 5774f8f669cSDavid du Colombier memset(m, 0, sizeof *m); 5783e12c5d1SDavid du Colombier USHORT(m->id); 5793e12c5d1SDavid du Colombier USHORT(m->flags); 5803e12c5d1SDavid du Colombier USHORT(m->qdcount); 5813e12c5d1SDavid du Colombier USHORT(m->ancount); 5823e12c5d1SDavid du Colombier USHORT(m->nscount); 5833e12c5d1SDavid du Colombier USHORT(m->arcount); 5844f8f669cSDavid du Colombier 5854f8f669cSDavid du Colombier m->qd = rrloop(sp, "questions", m->qdcount, 1); 5864f8f669cSDavid du Colombier m->an = rrloop(sp, "answers", m->ancount, 0); 5874f8f669cSDavid du Colombier m->ns = rrloop(sp, "nameservers",m->nscount, 0); 5880319257bSDavid du Colombier if (sp->stop) 5890319257bSDavid du Colombier sp->err = nil; 5900319257bSDavid du Colombier if (sp->err) 5910319257bSDavid du Colombier err = strdup(sp->err); /* live with bad ar's */ 5924f8f669cSDavid du Colombier m->ar = rrloop(sp, "hints", m->arcount, 0); 5930319257bSDavid du Colombier if (sp->trunc) 594a41547ffSDavid du Colombier m->flags |= Ftrunc; 5950319257bSDavid du Colombier if (sp->stop) 596d9924332SDavid du Colombier sp->rcode = Rok; 5974f8f669cSDavid du Colombier if (codep) 5980319257bSDavid du Colombier *codep = sp->rcode; 5997dd7cddfSDavid du Colombier return err; 6003e12c5d1SDavid du Colombier } 601