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
errneg(RR * rp,Scan * sp,int actual)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
errtoolong(RR * rp,Scan * sp,int remain,int need,char * where)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)
44401db9f5SDavid du Colombier p = seprint(p, ep, ": %R", rp);
45401db9f5SDavid du Colombier /*
46401db9f5SDavid du Colombier * hack to cope with servers that don't set Ftrunc when they should:
47401db9f5SDavid du Colombier * if the (udp) packet is full-sized, if must be truncated because
48401db9f5SDavid du Colombier * it is incomplete. otherwise, it's just garbled.
49401db9f5SDavid du Colombier */
50*98813beeSDavid du Colombier if (sp->ep - sp->base >= Maxpayload) {
51a41547ffSDavid du Colombier sp->trunc = 1;
52401db9f5SDavid du Colombier seprint(p, ep, " (truncated)");
53401db9f5SDavid du Colombier }
5482f6abeeSDavid du Colombier if (debug && rp)
55b8b25780SDavid du Colombier dnslog("malformed rr: %R", rp);
56401db9f5SDavid 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
gchar(RR * rp,Scan * sp)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
gshort(RR * rp,Scan * sp)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
glong(RR * rp,Scan * sp)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*
gv4addr(RR * rp,Scan * sp)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*
gv6addr(RR * rp,Scan * sp)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*
gsym(RR * rp,Scan * sp)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*
gstr(RR * rp,Scan * sp)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
gbytes(RR * rp,Scan * sp,uchar ** p,int n)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*
gname(char * to,RR * rp,Scan * sp)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;
265*98813beeSDavid du Colombier case 0100: /* edns extended label type, rfc 6891 */
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
mstypehack(Scan * sp,ushort type,char * where)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*
convM2RR(Scan * sp,char * what)3344f8f669cSDavid du Colombier convM2RR(Scan *sp, char *what)
3353e12c5d1SDavid du Colombier {
33682f6abeeSDavid du Colombier int type, class, len, left;
337401db9f5SDavid 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);
406401db9f5SDavid du Colombier dn = NAME(dname);
407401db9f5SDavid du Colombier rp->host = dnlookup(dn, Cin, 1);
408401db9f5SDavid du Colombier if(strchr((char *)rp->host, '\n') != nil) {
409401db9f5SDavid du Colombier dnslog("newline in mx text for %s", dn);
410401db9f5SDavid du Colombier sp->trunc = 1; /* try again via tcp */
411401db9f5SDavid 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*
convM2Q(Scan * sp)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*
rrloop(Scan * sp,char * what,int count,int quest)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.
570401db9f5SDavid du Colombier *
571*98813beeSDavid du Colombier * ideally would note if len == Maxpayload && query was via UDP, for errtoolong.
5723e12c5d1SDavid du Colombier */
5733e12c5d1SDavid du Colombier char*
convM2DNS(uchar * buf,int len,DNSmsg * m,int * codep)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