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 { 982f6abeeSDavid du Colombier uchar *base; /* input buffer */ 1082f6abeeSDavid du Colombier uchar *p; /* current position */ 1182f6abeeSDavid 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) 44*401db9f5SDavid du Colombier p = seprint(p, ep, ": %R", rp); 45*401db9f5SDavid du Colombier /* 46*401db9f5SDavid du Colombier * hack to cope with servers that don't set Ftrunc when they should: 47*401db9f5SDavid du Colombier * if the (udp) packet is full-sized, if must be truncated because 48*401db9f5SDavid du Colombier * it is incomplete. otherwise, it's just garbled. 49*401db9f5SDavid du Colombier */ 50*401db9f5SDavid du Colombier if (sp->ep - sp->base >= Maxudp) { 51a41547ffSDavid du Colombier sp->trunc = 1; 52*401db9f5SDavid du Colombier seprint(p, ep, " (truncated)"); 53*401db9f5SDavid du Colombier } 5482f6abeeSDavid du Colombier if (debug && rp) 55b8b25780SDavid du Colombier dnslog("malformed rr: %R", rp); 56*401db9f5SDavid du Colombier sp->err = sp->errbuf; 574f8f669cSDavid du Colombier return 0; 584f8f669cSDavid du Colombier } 593e12c5d1SDavid du Colombier 603e12c5d1SDavid du Colombier /* 613e12c5d1SDavid du Colombier * get a ushort/ulong 623e12c5d1SDavid du Colombier */ 633e12c5d1SDavid du Colombier static ushort 644f8f669cSDavid du Colombier gchar(RR *rp, Scan *sp) 657dd7cddfSDavid du Colombier { 667dd7cddfSDavid du Colombier ushort x; 677dd7cddfSDavid du Colombier 687dd7cddfSDavid du Colombier if(sp->err) 697dd7cddfSDavid du Colombier return 0; 704f8f669cSDavid du Colombier if(sp->ep - sp->p < 1) 714f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar"); 727dd7cddfSDavid du Colombier x = sp->p[0]; 737dd7cddfSDavid du Colombier sp->p += 1; 747dd7cddfSDavid du Colombier return x; 757dd7cddfSDavid du Colombier } 767dd7cddfSDavid du Colombier static ushort 774f8f669cSDavid du Colombier gshort(RR *rp, Scan *sp) 783e12c5d1SDavid du Colombier { 793e12c5d1SDavid du Colombier ushort x; 803e12c5d1SDavid du Colombier 813e12c5d1SDavid du Colombier if(sp->err) 823e12c5d1SDavid du Colombier return 0; 834f8f669cSDavid du Colombier if(sp->ep - sp->p < 2) 844f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort"); 854f8f669cSDavid du Colombier x = sp->p[0]<<8 | sp->p[1]; 863e12c5d1SDavid du Colombier sp->p += 2; 873e12c5d1SDavid du Colombier return x; 883e12c5d1SDavid du Colombier } 893e12c5d1SDavid du Colombier static ulong 904f8f669cSDavid du Colombier glong(RR *rp, Scan *sp) 913e12c5d1SDavid du Colombier { 923e12c5d1SDavid du Colombier ulong x; 933e12c5d1SDavid du Colombier 943e12c5d1SDavid du Colombier if(sp->err) 953e12c5d1SDavid du Colombier return 0; 964f8f669cSDavid du Colombier if(sp->ep - sp->p < 4) 974f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong"); 984f8f669cSDavid du Colombier x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3]; 993e12c5d1SDavid du Colombier sp->p += 4; 1003e12c5d1SDavid du Colombier return x; 1013e12c5d1SDavid du Colombier } 1023e12c5d1SDavid du Colombier 1033e12c5d1SDavid du Colombier /* 1043e12c5d1SDavid du Colombier * get an ip address 1053e12c5d1SDavid du Colombier */ 1063e12c5d1SDavid du Colombier static DN* 1074f8f669cSDavid du Colombier gv4addr(RR *rp, Scan *sp) 1083e12c5d1SDavid du Colombier { 1093e12c5d1SDavid du Colombier char addr[32]; 1103e12c5d1SDavid du Colombier 1113e12c5d1SDavid du Colombier if(sp->err) 1123e12c5d1SDavid du Colombier return 0; 1134f8f669cSDavid du Colombier if(sp->ep - sp->p < 4) 1144f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr"); 1154f8f669cSDavid du Colombier snprint(addr, sizeof addr, "%V", sp->p); 1163e12c5d1SDavid du Colombier sp->p += 4; 1173e12c5d1SDavid du Colombier 1183e12c5d1SDavid du Colombier return dnlookup(addr, Cin, 1); 1193e12c5d1SDavid du Colombier } 1205d459b5aSDavid du Colombier static DN* 1214f8f669cSDavid du Colombier gv6addr(RR *rp, Scan *sp) 1225d459b5aSDavid du Colombier { 1235d459b5aSDavid du Colombier char addr[64]; 1245d459b5aSDavid du Colombier 1255d459b5aSDavid du Colombier if(sp->err) 1265d459b5aSDavid du Colombier return 0; 1274f8f669cSDavid du Colombier if(sp->ep - sp->p < IPaddrlen) 1284f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen, 1294f8f669cSDavid du Colombier "gv6addr"); 1304f8f669cSDavid du Colombier snprint(addr, sizeof addr, "%I", sp->p); 1315d459b5aSDavid du Colombier sp->p += IPaddrlen; 1325d459b5aSDavid du Colombier 1335d459b5aSDavid du Colombier return dnlookup(addr, Cin, 1); 1345d459b5aSDavid du Colombier } 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier /* 1373e12c5d1SDavid du Colombier * get a string. make it an internal symbol. 1383e12c5d1SDavid du Colombier */ 1393e12c5d1SDavid du Colombier static DN* 1404f8f669cSDavid du Colombier gsym(RR *rp, Scan *sp) 1413e12c5d1SDavid du Colombier { 1423e12c5d1SDavid du Colombier int n; 1433e12c5d1SDavid du Colombier char sym[Strlen+1]; 1443e12c5d1SDavid du Colombier 1453e12c5d1SDavid du Colombier if(sp->err) 1463e12c5d1SDavid du Colombier return 0; 1474f8f669cSDavid du Colombier n = 0; 1484f8f669cSDavid du Colombier if (sp->p < sp->ep) 1493e12c5d1SDavid du Colombier n = *(sp->p++); 1504f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 1514f8f669cSDavid du Colombier return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym"); 1523e12c5d1SDavid du Colombier 1533e12c5d1SDavid du Colombier if(n > Strlen){ 1544f8f669cSDavid du Colombier sp->err = "illegal string (symbol)"; 1553e12c5d1SDavid du Colombier return 0; 1563e12c5d1SDavid du Colombier } 1573e12c5d1SDavid du Colombier strncpy(sym, (char*)sp->p, n); 1583e12c5d1SDavid du Colombier sym[n] = 0; 1594f8f669cSDavid du Colombier if (strlen(sym) != n) 1604f8f669cSDavid du Colombier sp->err = "symbol shorter than declared length"; 1613e12c5d1SDavid du Colombier sp->p += n; 1623e12c5d1SDavid du Colombier 1633e12c5d1SDavid du Colombier return dnlookup(sym, Csym, 1); 1643e12c5d1SDavid du Colombier } 1653e12c5d1SDavid du Colombier 1663e12c5d1SDavid du Colombier /* 16760845620SDavid du Colombier * get a string. don't make it an internal symbol. 16860845620SDavid du Colombier */ 16960845620SDavid du Colombier static Txt* 1704f8f669cSDavid du Colombier gstr(RR *rp, Scan *sp) 17160845620SDavid du Colombier { 17260845620SDavid du Colombier int n; 17360845620SDavid du Colombier char sym[Strlen+1]; 17460845620SDavid du Colombier Txt *t; 17560845620SDavid du Colombier 17660845620SDavid du Colombier if(sp->err) 17760845620SDavid du Colombier return 0; 1784f8f669cSDavid du Colombier n = 0; 1794f8f669cSDavid du Colombier if (sp->p < sp->ep) 18060845620SDavid du Colombier n = *(sp->p++); 1814f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 1824f8f669cSDavid du Colombier return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr"); 18360845620SDavid du Colombier 18460845620SDavid du Colombier if(n > Strlen){ 18560845620SDavid du Colombier sp->err = "illegal string"; 18660845620SDavid du Colombier return 0; 18760845620SDavid du Colombier } 18860845620SDavid du Colombier strncpy(sym, (char*)sp->p, n); 18960845620SDavid du Colombier sym[n] = 0; 1904f8f669cSDavid du Colombier if (strlen(sym) != n) 1914f8f669cSDavid du Colombier sp->err = "string shorter than declared length"; 19260845620SDavid du Colombier sp->p += n; 19360845620SDavid du Colombier 19460845620SDavid du Colombier t = emalloc(sizeof(*t)); 19560845620SDavid du Colombier t->next = nil; 19660845620SDavid du Colombier t->p = estrdup(sym); 19760845620SDavid du Colombier return t; 19860845620SDavid du Colombier } 19960845620SDavid du Colombier 20060845620SDavid du Colombier /* 2017dd7cddfSDavid du Colombier * get a sequence of bytes 2027dd7cddfSDavid du Colombier */ 2037dd7cddfSDavid du Colombier static int 2044f8f669cSDavid du Colombier gbytes(RR *rp, Scan *sp, uchar **p, int n) 2057dd7cddfSDavid du Colombier { 2064f8f669cSDavid du Colombier *p = nil; /* i think this is a good idea */ 2077dd7cddfSDavid du Colombier if(sp->err) 2087dd7cddfSDavid du Colombier return 0; 2094f8f669cSDavid du Colombier if(n < 0) 2104f8f669cSDavid du Colombier return errneg(rp, sp, n); 2114f8f669cSDavid du Colombier if(sp->ep - sp->p < n) 2124f8f669cSDavid du Colombier return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes"); 2139a747e4fSDavid du Colombier *p = emalloc(n); 2147dd7cddfSDavid du Colombier memmove(*p, sp->p, n); 2157dd7cddfSDavid du Colombier sp->p += n; 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier return n; 2187dd7cddfSDavid du Colombier } 2197dd7cddfSDavid du Colombier 2207dd7cddfSDavid du Colombier /* 2213e12c5d1SDavid du Colombier * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 2223e12c5d1SDavid du Colombier */ 2233e12c5d1SDavid du Colombier static char* 2244f8f669cSDavid du Colombier gname(char *to, RR *rp, Scan *sp) 2253e12c5d1SDavid du Colombier { 2264f8f669cSDavid du Colombier int len, off, pointer, n; 2274f8f669cSDavid du Colombier char *tostart, *toend; 2283e12c5d1SDavid du Colombier uchar *p; 2293e12c5d1SDavid du Colombier 2303e12c5d1SDavid du Colombier tostart = to; 23176783259SDavid du Colombier if(sp->err || sp->stop) 2323e12c5d1SDavid du Colombier goto err; 2333e12c5d1SDavid du Colombier pointer = 0; 2343e12c5d1SDavid du Colombier p = sp->p; 23582f6abeeSDavid du Colombier if (p == nil) { 23682f6abeeSDavid du Colombier dnslog("gname: %R: nil sp->p", rp); 23782f6abeeSDavid du Colombier goto err; 23882f6abeeSDavid du Colombier } 2393e12c5d1SDavid du Colombier toend = to + Domlen; 24076783259SDavid du Colombier for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) { 24176783259SDavid du Colombier n = 0; 24276783259SDavid du Colombier switch (*p & 0300) { 24376783259SDavid du Colombier case 0: /* normal label */ 24476783259SDavid du Colombier if (p < sp->ep) 24576783259SDavid du Colombier n = *p++ & 077; /* pick up length */ 24676783259SDavid du Colombier if(len + n < Domlen - 1){ 24776783259SDavid du Colombier if(n > toend - to){ 24876783259SDavid du Colombier errtoolong(rp, sp, toend - to, n, 24976783259SDavid du Colombier "name too long"); 25076783259SDavid du Colombier goto err; 25176783259SDavid du Colombier } 25276783259SDavid du Colombier memmove(to, p, n); 25376783259SDavid du Colombier to += n; 25476783259SDavid du Colombier } 25576783259SDavid du Colombier p += n; 25676783259SDavid du Colombier if(*p){ 25776783259SDavid du Colombier if(to >= toend){ 25876783259SDavid du Colombier errtoolong(rp, sp, toend - to, 2, 25976783259SDavid du Colombier "more name components but no bytes left"); 26076783259SDavid du Colombier goto err; 26176783259SDavid du Colombier } 26276783259SDavid du Colombier *to++ = '.'; 26376783259SDavid du Colombier } 26476783259SDavid du Colombier break; 26576783259SDavid du Colombier case 0100: /* edns extended label type, rfc 2671 */ 26676783259SDavid du Colombier /* 26776783259SDavid du Colombier * treat it like an EOF for now; it seems to be at 26876783259SDavid du Colombier * the end of a long tcp reply. 26976783259SDavid du Colombier */ 2705d34ce99SDavid du Colombier dnslog("edns label; first byte 0%o = '%c'", *p, *p); 27176783259SDavid du Colombier sp->stop = 1; 27276783259SDavid du Colombier goto err; 27376783259SDavid du Colombier case 0200: /* reserved */ 27476783259SDavid du Colombier sp->err = "reserved-use label present"; 27576783259SDavid du Colombier goto err; 27676783259SDavid du Colombier case 0300: /* pointer to other spot in message */ 2773e12c5d1SDavid du Colombier if(pointer++ > 10){ 2783e12c5d1SDavid du Colombier sp->err = "pointer loop"; 2793e12c5d1SDavid du Colombier goto err; 2803e12c5d1SDavid du Colombier } 2815d34ce99SDavid du Colombier off = (p[0] & 077)<<8 | p[1]; 2823e12c5d1SDavid du Colombier p = sp->base + off; 2833e12c5d1SDavid du Colombier if(p >= sp->ep){ 2843e12c5d1SDavid du Colombier sp->err = "bad pointer"; 2853e12c5d1SDavid du Colombier goto err; 2863e12c5d1SDavid du Colombier } 2873e12c5d1SDavid du Colombier n = 0; 28876783259SDavid du Colombier break; 2893e12c5d1SDavid du Colombier } 2903e12c5d1SDavid du Colombier } 2913e12c5d1SDavid du Colombier *to = 0; 2923e12c5d1SDavid du Colombier if(pointer) 2933e12c5d1SDavid du Colombier sp->p += len + 2; /* + 2 for pointer */ 2943e12c5d1SDavid du Colombier else 2953e12c5d1SDavid du Colombier sp->p += len + 1; /* + 1 for the null domain */ 2963e12c5d1SDavid du Colombier return tostart; 2973e12c5d1SDavid du Colombier err: 2983e12c5d1SDavid du Colombier *tostart = 0; 2993e12c5d1SDavid du Colombier return tostart; 3003e12c5d1SDavid du Colombier } 3013e12c5d1SDavid du Colombier 3023e12c5d1SDavid du Colombier /* 3034f8f669cSDavid du Colombier * ms windows 2000 seems to get the bytes backward in the type field 3044f8f669cSDavid du Colombier * of ptr records, so return a format error as feedback. 3054f8f669cSDavid du Colombier */ 306d9924332SDavid du Colombier static ushort 307d9924332SDavid du Colombier mstypehack(Scan *sp, ushort type, char *where) 3084f8f669cSDavid du Colombier { 309d9924332SDavid du Colombier if ((uchar)type == 0 && (type>>8) != 0) { 3104f8f669cSDavid du Colombier USED(where); 3114f8f669cSDavid du Colombier // dnslog("%s: byte-swapped type field in ptr rr from win2k", 3124f8f669cSDavid du Colombier // where); 313d9924332SDavid du Colombier if (sp->rcode == Rok) 3144f8f669cSDavid du Colombier sp->rcode = Rformat; 31582f6abeeSDavid du Colombier type >>= 8; 3164f8f669cSDavid du Colombier } 317d9924332SDavid du Colombier return type; 3184f8f669cSDavid du Colombier } 3194f8f669cSDavid du Colombier 32082f6abeeSDavid du Colombier #define NAME(x) gname(x, rp, sp) 32182f6abeeSDavid du Colombier #define SYMBOL(x) ((x) = gsym(rp, sp)) 32282f6abeeSDavid du Colombier #define STRING(x) ((x) = gstr(rp, sp)) 32382f6abeeSDavid du Colombier #define USHORT(x) ((x) = gshort(rp, sp)) 32482f6abeeSDavid du Colombier #define ULONG(x) ((x) = glong(rp, sp)) 32582f6abeeSDavid du Colombier #define UCHAR(x) ((x) = gchar(rp, sp)) 32682f6abeeSDavid du Colombier #define V4ADDR(x) ((x) = gv4addr(rp, sp)) 32782f6abeeSDavid du Colombier #define V6ADDR(x) ((x) = gv6addr(rp, sp)) 32882f6abeeSDavid du Colombier #define BYTES(x, y) ((y) = gbytes(rp, sp, &(x), len - (sp->p - data))) 32982f6abeeSDavid du Colombier 3304f8f669cSDavid du Colombier /* 3313e12c5d1SDavid du Colombier * convert the next RR from a message 3323e12c5d1SDavid du Colombier */ 3333e12c5d1SDavid du Colombier static RR* 3344f8f669cSDavid du Colombier convM2RR(Scan *sp, char *what) 3353e12c5d1SDavid du Colombier { 33682f6abeeSDavid du Colombier int type, class, len, left; 337*401db9f5SDavid du Colombier char *dn; 3383e12c5d1SDavid du Colombier char dname[Domlen+1]; 3394f8f669cSDavid du Colombier uchar *data; 34082f6abeeSDavid du Colombier RR *rp; 34160845620SDavid du Colombier Txt *t, **l; 3423e12c5d1SDavid du Colombier 3437dd7cddfSDavid du Colombier retry: 34482f6abeeSDavid du Colombier rp = nil; 3453e12c5d1SDavid du Colombier NAME(dname); 3463e12c5d1SDavid du Colombier USHORT(type); 3473e12c5d1SDavid du Colombier USHORT(class); 3483e12c5d1SDavid du Colombier 349d9924332SDavid du Colombier type = mstypehack(sp, type, "convM2RR"); 3503e12c5d1SDavid du Colombier rp = rralloc(type); 3513e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 3523e12c5d1SDavid du Colombier rp->type = type; 3533e12c5d1SDavid du Colombier 3543e12c5d1SDavid du Colombier ULONG(rp->ttl); 3557dd7cddfSDavid du Colombier rp->ttl += now; 35682f6abeeSDavid du Colombier USHORT(len); /* length of data following */ 3573e12c5d1SDavid du Colombier data = sp->p; 35882f6abeeSDavid du Colombier assert(data != nil); 35982f6abeeSDavid du Colombier left = sp->ep - sp->p; 3607dd7cddfSDavid du Colombier 3614f8f669cSDavid du Colombier /* 3624f8f669cSDavid du Colombier * ms windows generates a lot of badly-formatted hints. 3634f8f669cSDavid du Colombier * hints are only advisory, so don't log complaints about them. 3644f8f669cSDavid du Colombier * it also generates answers in which p overshoots ep by exactly 3654f8f669cSDavid du Colombier * one byte; this seems to be harmless, so don't log them either. 3664f8f669cSDavid du Colombier */ 36782f6abeeSDavid du Colombier if (len > left && 3684f8f669cSDavid du Colombier !(strcmp(what, "hints") == 0 || 36976783259SDavid du Colombier sp->p == sp->ep + 1 && strcmp(what, "answers") == 0)) 37082f6abeeSDavid du Colombier errtoolong(rp, sp, left, len, "convM2RR"); 37176783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop){ 3727dd7cddfSDavid du Colombier rrfree(rp); 3735d34ce99SDavid du Colombier return nil; 3747dd7cddfSDavid du Colombier } 37582f6abeeSDavid du Colombier /* even if we don't log an error message, truncate length to fit data */ 37682f6abeeSDavid du Colombier if (len > left) 37782f6abeeSDavid du Colombier len = left; 3787dd7cddfSDavid du Colombier 3793e12c5d1SDavid du Colombier switch(type){ 3807dd7cddfSDavid du Colombier default: 3817dd7cddfSDavid du Colombier /* unknown type, just ignore it */ 3827dd7cddfSDavid du Colombier sp->p = data + len; 3837dd7cddfSDavid du Colombier rrfree(rp); 3847dd7cddfSDavid du Colombier goto retry; 3853e12c5d1SDavid du Colombier case Thinfo: 38660845620SDavid du Colombier SYMBOL(rp->cpu); 38760845620SDavid du Colombier SYMBOL(rp->os); 3883e12c5d1SDavid du Colombier break; 3893e12c5d1SDavid du Colombier case Tcname: 3903e12c5d1SDavid du Colombier case Tmb: 3913e12c5d1SDavid du Colombier case Tmd: 3923e12c5d1SDavid du Colombier case Tmf: 3933e12c5d1SDavid du Colombier case Tns: 3943e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 3953e12c5d1SDavid du Colombier break; 3963e12c5d1SDavid du Colombier case Tmg: 3973e12c5d1SDavid du Colombier case Tmr: 3983e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 3993e12c5d1SDavid du Colombier break; 4003e12c5d1SDavid du Colombier case Tminfo: 4013e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 4023e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 4033e12c5d1SDavid du Colombier break; 4043e12c5d1SDavid du Colombier case Tmx: 4053e12c5d1SDavid du Colombier USHORT(rp->pref); 406*401db9f5SDavid du Colombier dn = NAME(dname); 407*401db9f5SDavid du Colombier rp->host = dnlookup(dn, Cin, 1); 408*401db9f5SDavid du Colombier if(strchr((char *)rp->host, '\n') != nil) { 409*401db9f5SDavid du Colombier dnslog("newline in mx text for %s", dn); 410*401db9f5SDavid du Colombier sp->trunc = 1; /* try again via tcp */ 411*401db9f5SDavid du Colombier } 4123e12c5d1SDavid du Colombier break; 4133e12c5d1SDavid du Colombier case Ta: 4145d459b5aSDavid du Colombier V4ADDR(rp->ip); 4155d459b5aSDavid du Colombier break; 4165d459b5aSDavid du Colombier case Taaaa: 4175d459b5aSDavid du Colombier V6ADDR(rp->ip); 4183e12c5d1SDavid du Colombier break; 4193e12c5d1SDavid du Colombier case Tptr: 4203e12c5d1SDavid du Colombier rp->ptr = dnlookup(NAME(dname), Cin, 1); 4213e12c5d1SDavid du Colombier break; 4223e12c5d1SDavid du Colombier case Tsoa: 4233e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 4243e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 4253e12c5d1SDavid du Colombier ULONG(rp->soa->serial); 4263e12c5d1SDavid du Colombier ULONG(rp->soa->refresh); 4273e12c5d1SDavid du Colombier ULONG(rp->soa->retry); 4283e12c5d1SDavid du Colombier ULONG(rp->soa->expire); 4293e12c5d1SDavid du Colombier ULONG(rp->soa->minttl); 4303e12c5d1SDavid du Colombier break; 4314f8f669cSDavid du Colombier case Tsrv: 4324f8f669cSDavid du Colombier USHORT(rp->srv->pri); 4334f8f669cSDavid du Colombier USHORT(rp->srv->weight); 434225077b0SDavid du Colombier USHORT(rp->port); 435225077b0SDavid du Colombier /* 436225077b0SDavid du Colombier * rfc2782 sez no name compression but to be 437225077b0SDavid du Colombier * backward-compatible with rfc2052, we try to expand the name. 438225077b0SDavid du Colombier * if the length is under 64 bytes, either interpretation is 439225077b0SDavid du Colombier * fine; if it's longer, we'll assume it's compressed, 440225077b0SDavid du Colombier * as recommended by rfc3597. 441225077b0SDavid du Colombier */ 442225077b0SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 4434f8f669cSDavid du Colombier break; 4447dd7cddfSDavid du Colombier case Ttxt: 44560845620SDavid du Colombier l = &rp->txt; 44660845620SDavid du Colombier *l = nil; 44760845620SDavid du Colombier while(sp->p - data < len){ 44860845620SDavid du Colombier STRING(t); 44960845620SDavid du Colombier *l = t; 45060845620SDavid du Colombier l = &t->next; 45160845620SDavid du Colombier } 4527dd7cddfSDavid du Colombier break; 4539a747e4fSDavid du Colombier case Tnull: 4549a747e4fSDavid du Colombier BYTES(rp->null->data, rp->null->dlen); 4559a747e4fSDavid du Colombier break; 4567dd7cddfSDavid du Colombier case Trp: 4577dd7cddfSDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 45860845620SDavid du Colombier rp->rp = dnlookup(NAME(dname), Cin, 1); 4597dd7cddfSDavid du Colombier break; 4607dd7cddfSDavid du Colombier case Tkey: 4617dd7cddfSDavid du Colombier USHORT(rp->key->flags); 4627dd7cddfSDavid du Colombier UCHAR(rp->key->proto); 4637dd7cddfSDavid du Colombier UCHAR(rp->key->alg); 4647dd7cddfSDavid du Colombier BYTES(rp->key->data, rp->key->dlen); 4657dd7cddfSDavid du Colombier break; 4667dd7cddfSDavid du Colombier case Tsig: 4677dd7cddfSDavid du Colombier USHORT(rp->sig->type); 4687dd7cddfSDavid du Colombier UCHAR(rp->sig->alg); 4697dd7cddfSDavid du Colombier UCHAR(rp->sig->labels); 4707dd7cddfSDavid du Colombier ULONG(rp->sig->ttl); 4717dd7cddfSDavid du Colombier ULONG(rp->sig->exp); 4727dd7cddfSDavid du Colombier ULONG(rp->sig->incep); 4737dd7cddfSDavid du Colombier USHORT(rp->sig->tag); 4747dd7cddfSDavid du Colombier rp->sig->signer = dnlookup(NAME(dname), Cin, 1); 4757dd7cddfSDavid du Colombier BYTES(rp->sig->data, rp->sig->dlen); 4767dd7cddfSDavid du Colombier break; 4777dd7cddfSDavid du Colombier case Tcert: 4787dd7cddfSDavid du Colombier USHORT(rp->cert->type); 4797dd7cddfSDavid du Colombier USHORT(rp->cert->tag); 4807dd7cddfSDavid du Colombier UCHAR(rp->cert->alg); 4817dd7cddfSDavid du Colombier BYTES(rp->cert->data, rp->cert->dlen); 4827dd7cddfSDavid du Colombier break; 4833e12c5d1SDavid du Colombier } 4844f8f669cSDavid du Colombier if(sp->p - data != len) { 4854f8f669cSDavid du Colombier char ptype[64]; 4864f8f669cSDavid du Colombier 4874f8f669cSDavid du Colombier /* 4884f8f669cSDavid du Colombier * ms windows 2000 generates cname queries for reverse lookups 4894f8f669cSDavid du Colombier * with this particular error. don't bother logging it. 4904f8f669cSDavid du Colombier * 4914f8f669cSDavid du Colombier * server: input error: bad cname RR len (actual 2 != len 0): 4924f8f669cSDavid du Colombier * 235.9.104.135.in-addr.arpa cname 4934f8f669cSDavid du Colombier * 235.9.104.135.in-addr.arpa from 135.104.9.235 4944f8f669cSDavid du Colombier */ 495b8b25780SDavid du Colombier if (type == Tcname && sp->p - data == 2 && len == 0) 4964f8f669cSDavid du Colombier return rp; 497225077b0SDavid du Colombier if (len > sp->p - data){ 49876783259SDavid du Colombier dnslog("bad %s RR len (%d bytes nominal, %lud actual): %R", 49976783259SDavid du Colombier rrname(type, ptype, sizeof ptype), len, 50076783259SDavid du Colombier sp->p - data, rp); 501225077b0SDavid du Colombier rrfree(rp); 502225077b0SDavid du Colombier rp = nil; 50376783259SDavid du Colombier } 504225077b0SDavid du Colombier } 505225077b0SDavid du Colombier // if(rp) dnslog("convM2RR: got %R", rp); 5063e12c5d1SDavid du Colombier return rp; 5073e12c5d1SDavid du Colombier } 5083e12c5d1SDavid du Colombier 5093e12c5d1SDavid du Colombier /* 5103e12c5d1SDavid du Colombier * convert the next question from a message 5113e12c5d1SDavid du Colombier */ 5123e12c5d1SDavid du Colombier static RR* 5133e12c5d1SDavid du Colombier convM2Q(Scan *sp) 5143e12c5d1SDavid du Colombier { 5153e12c5d1SDavid du Colombier char dname[Domlen+1]; 5164f8f669cSDavid du Colombier int type, class; 51782f6abeeSDavid du Colombier RR *rp; 5183e12c5d1SDavid du Colombier 51982f6abeeSDavid du Colombier rp = nil; 5203e12c5d1SDavid du Colombier NAME(dname); 5213e12c5d1SDavid du Colombier USHORT(type); 5223e12c5d1SDavid du Colombier USHORT(class); 52376783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop) 5244f8f669cSDavid du Colombier return nil; 5253e12c5d1SDavid du Colombier 526d9924332SDavid du Colombier type = mstypehack(sp, type, "convM2Q"); 5273e12c5d1SDavid du Colombier rp = rralloc(type); 5283e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 5293e12c5d1SDavid du Colombier 5303e12c5d1SDavid du Colombier return rp; 5313e12c5d1SDavid du Colombier } 5323e12c5d1SDavid du Colombier 5333e12c5d1SDavid du Colombier static RR* 5344f8f669cSDavid du Colombier rrloop(Scan *sp, char *what, int count, int quest) 5353e12c5d1SDavid du Colombier { 5363e12c5d1SDavid du Colombier int i; 5373e12c5d1SDavid du Colombier RR *first, *rp, **l; 5383e12c5d1SDavid du Colombier 53976783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop) 5404f8f669cSDavid du Colombier return nil; 5413e12c5d1SDavid du Colombier l = &first; 5424f8f669cSDavid du Colombier first = nil; 5433e12c5d1SDavid du Colombier for(i = 0; i < count; i++){ 5444f8f669cSDavid du Colombier rp = quest? convM2Q(sp): convM2RR(sp, what); 5454f8f669cSDavid du Colombier if(rp == nil) 546bd389b36SDavid du Colombier break; 5475d34ce99SDavid du Colombier setmalloctag(rp, getcallerpc(&sp)); 548b8b25780SDavid du Colombier /* 549b8b25780SDavid du Colombier * it might be better to ignore the bad rr, possibly break out, 550b8b25780SDavid du Colombier * but return the previous rrs, if any. that way our callers 551b8b25780SDavid du Colombier * would know that they had got a response, however ill-formed. 552b8b25780SDavid du Colombier */ 55376783259SDavid du Colombier if(sp->err || sp->rcode || sp->stop){ 5543e12c5d1SDavid du Colombier rrfree(rp); 5553e12c5d1SDavid du Colombier break; 5563e12c5d1SDavid du Colombier } 5573e12c5d1SDavid du Colombier *l = rp; 5583e12c5d1SDavid du Colombier l = &rp->next; 5593e12c5d1SDavid du Colombier } 56082f6abeeSDavid du Colombier // if(first) 5615d34ce99SDavid du Colombier // setmalloctag(first, getcallerpc(&sp)); 5623e12c5d1SDavid du Colombier return first; 5633e12c5d1SDavid du Colombier } 5643e12c5d1SDavid du Colombier 5653e12c5d1SDavid du Colombier /* 5664f8f669cSDavid du Colombier * convert the next DNS from a message stream. 5674f8f669cSDavid du Colombier * if there are formatting errors or the like during parsing of the message, 5684f8f669cSDavid du Colombier * set *codep to the outgoing response code (e.g., Rformat), which will 5694f8f669cSDavid du Colombier * abort processing and reply immediately with the outgoing response code. 570*401db9f5SDavid du Colombier * 571*401db9f5SDavid du Colombier * ideally would note if len == Maxudp && query was via UDP, for errtoolong. 5723e12c5d1SDavid du Colombier */ 5733e12c5d1SDavid du Colombier char* 5744f8f669cSDavid du Colombier convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep) 5753e12c5d1SDavid du Colombier { 576186d659cSDavid du Colombier char *err = nil; 5774f8f669cSDavid du Colombier RR *rp = nil; 5780319257bSDavid du Colombier Scan scan; 5790319257bSDavid du Colombier Scan *sp; 5803e12c5d1SDavid du Colombier 5814f8f669cSDavid du Colombier assert(len >= 0); 58282f6abeeSDavid du Colombier assert(buf != nil); 5833e12c5d1SDavid du Colombier sp = &scan; 5840319257bSDavid du Colombier memset(sp, 0, sizeof *sp); 5850319257bSDavid du Colombier sp->base = sp->p = buf; 5860319257bSDavid du Colombier sp->ep = buf + len; 5870319257bSDavid du Colombier sp->err = nil; 5880319257bSDavid du Colombier sp->errbuf[0] = '\0'; 58982f6abeeSDavid du Colombier sp->rcode = Rok; 5904f8f669cSDavid du Colombier 5914f8f669cSDavid du Colombier memset(m, 0, sizeof *m); 5923e12c5d1SDavid du Colombier USHORT(m->id); 5933e12c5d1SDavid du Colombier USHORT(m->flags); 5943e12c5d1SDavid du Colombier USHORT(m->qdcount); 5953e12c5d1SDavid du Colombier USHORT(m->ancount); 5963e12c5d1SDavid du Colombier USHORT(m->nscount); 5973e12c5d1SDavid du Colombier USHORT(m->arcount); 5984f8f669cSDavid du Colombier 5994f8f669cSDavid du Colombier m->qd = rrloop(sp, "questions", m->qdcount, 1); 6004f8f669cSDavid du Colombier m->an = rrloop(sp, "answers", m->ancount, 0); 6014f8f669cSDavid du Colombier m->ns = rrloop(sp, "nameservers",m->nscount, 0); 6020319257bSDavid du Colombier if (sp->stop) 6030319257bSDavid du Colombier sp->err = nil; 6040319257bSDavid du Colombier if (sp->err) 6050319257bSDavid du Colombier err = strdup(sp->err); /* live with bad ar's */ 6064f8f669cSDavid du Colombier m->ar = rrloop(sp, "hints", m->arcount, 0); 6070319257bSDavid du Colombier if (sp->trunc) 608a41547ffSDavid du Colombier m->flags |= Ftrunc; 6090319257bSDavid du Colombier if (sp->stop) 610d9924332SDavid du Colombier sp->rcode = Rok; 6114f8f669cSDavid du Colombier if (codep) 6120319257bSDavid du Colombier *codep = sp->rcode; 6137dd7cddfSDavid du Colombier return err; 6143e12c5d1SDavid du Colombier } 615