1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include "dns.h" 4*3e12c5d1SDavid du Colombier 5*3e12c5d1SDavid du Colombier typedef struct Scan Scan; 6*3e12c5d1SDavid du Colombier struct Scan 7*3e12c5d1SDavid du Colombier { 8*3e12c5d1SDavid du Colombier uchar *base; 9*3e12c5d1SDavid du Colombier uchar *p; 10*3e12c5d1SDavid du Colombier uchar *ep; 11*3e12c5d1SDavid du Colombier char *err; 12*3e12c5d1SDavid du Colombier }; 13*3e12c5d1SDavid du Colombier 14*3e12c5d1SDavid du Colombier #define NAME(x) gname(x, sp) 15*3e12c5d1SDavid du Colombier #define STRING(x) (x = gstr(sp)) 16*3e12c5d1SDavid du Colombier #define USHORT(x) (x = gshort(sp)) 17*3e12c5d1SDavid du Colombier #define ULONG(x) (x = glong(sp)) 18*3e12c5d1SDavid du Colombier #define ADDR(x) (x = gaddr(sp)) 19*3e12c5d1SDavid du Colombier 20*3e12c5d1SDavid du Colombier static char *toolong = "too long"; 21*3e12c5d1SDavid du Colombier 22*3e12c5d1SDavid du Colombier /* 23*3e12c5d1SDavid du Colombier * get a ushort/ulong 24*3e12c5d1SDavid du Colombier */ 25*3e12c5d1SDavid du Colombier static ushort 26*3e12c5d1SDavid du Colombier gshort(Scan *sp) 27*3e12c5d1SDavid du Colombier { 28*3e12c5d1SDavid du Colombier ushort x; 29*3e12c5d1SDavid du Colombier 30*3e12c5d1SDavid du Colombier if(sp->err) 31*3e12c5d1SDavid du Colombier return 0; 32*3e12c5d1SDavid du Colombier if(sp->ep - sp->p < 2){ 33*3e12c5d1SDavid du Colombier sp->err = toolong; 34*3e12c5d1SDavid du Colombier return 0; 35*3e12c5d1SDavid du Colombier } 36*3e12c5d1SDavid du Colombier x = (sp->p[0]<<8) | sp->p[1]; 37*3e12c5d1SDavid du Colombier sp->p += 2; 38*3e12c5d1SDavid du Colombier return x; 39*3e12c5d1SDavid du Colombier } 40*3e12c5d1SDavid du Colombier static ulong 41*3e12c5d1SDavid du Colombier glong(Scan *sp) 42*3e12c5d1SDavid du Colombier { 43*3e12c5d1SDavid du Colombier ulong x; 44*3e12c5d1SDavid du Colombier 45*3e12c5d1SDavid du Colombier if(sp->err) 46*3e12c5d1SDavid du Colombier return 0; 47*3e12c5d1SDavid du Colombier if(sp->ep - sp->p < 4){ 48*3e12c5d1SDavid du Colombier sp->err = toolong; 49*3e12c5d1SDavid du Colombier return 0; 50*3e12c5d1SDavid du Colombier } 51*3e12c5d1SDavid du Colombier x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3]; 52*3e12c5d1SDavid du Colombier sp->p += 4; 53*3e12c5d1SDavid du Colombier return x; 54*3e12c5d1SDavid du Colombier } 55*3e12c5d1SDavid du Colombier 56*3e12c5d1SDavid du Colombier /* 57*3e12c5d1SDavid du Colombier * get an ip address 58*3e12c5d1SDavid du Colombier */ 59*3e12c5d1SDavid du Colombier static DN* 60*3e12c5d1SDavid du Colombier gaddr(Scan *sp) 61*3e12c5d1SDavid du Colombier { 62*3e12c5d1SDavid du Colombier char addr[32]; 63*3e12c5d1SDavid du Colombier 64*3e12c5d1SDavid du Colombier if(sp->err) 65*3e12c5d1SDavid du Colombier return 0; 66*3e12c5d1SDavid du Colombier if(sp->ep - sp->p < 4){ 67*3e12c5d1SDavid du Colombier sp->err = toolong; 68*3e12c5d1SDavid du Colombier return 0; 69*3e12c5d1SDavid du Colombier } 70*3e12c5d1SDavid du Colombier sprint(addr, "%I", sp->p); 71*3e12c5d1SDavid du Colombier sp->p += 4; 72*3e12c5d1SDavid du Colombier 73*3e12c5d1SDavid du Colombier return dnlookup(addr, Cin, 1); 74*3e12c5d1SDavid du Colombier } 75*3e12c5d1SDavid du Colombier 76*3e12c5d1SDavid du Colombier /* 77*3e12c5d1SDavid du Colombier * get a string. make it an internal symbol. 78*3e12c5d1SDavid du Colombier */ 79*3e12c5d1SDavid du Colombier static DN* 80*3e12c5d1SDavid du Colombier gstr(Scan *sp) 81*3e12c5d1SDavid du Colombier { 82*3e12c5d1SDavid du Colombier int n; 83*3e12c5d1SDavid du Colombier char sym[Strlen+1]; 84*3e12c5d1SDavid du Colombier 85*3e12c5d1SDavid du Colombier if(sp->err) 86*3e12c5d1SDavid du Colombier return 0; 87*3e12c5d1SDavid du Colombier n = *(sp->p++); 88*3e12c5d1SDavid du Colombier if(sp->p+n > sp->ep){ 89*3e12c5d1SDavid du Colombier sp->err = toolong; 90*3e12c5d1SDavid du Colombier return 0; 91*3e12c5d1SDavid du Colombier } 92*3e12c5d1SDavid du Colombier 93*3e12c5d1SDavid du Colombier if(n > Strlen){ 94*3e12c5d1SDavid du Colombier sp->err = "illegal string"; 95*3e12c5d1SDavid du Colombier return 0; 96*3e12c5d1SDavid du Colombier } 97*3e12c5d1SDavid du Colombier strncpy(sym, (char*)sp->p, n); 98*3e12c5d1SDavid du Colombier sym[n] = 0; 99*3e12c5d1SDavid du Colombier sp->p += n; 100*3e12c5d1SDavid du Colombier 101*3e12c5d1SDavid du Colombier return dnlookup(sym, Csym, 1); 102*3e12c5d1SDavid du Colombier } 103*3e12c5d1SDavid du Colombier 104*3e12c5d1SDavid du Colombier /* 105*3e12c5d1SDavid du Colombier * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 106*3e12c5d1SDavid du Colombier */ 107*3e12c5d1SDavid du Colombier static char* 108*3e12c5d1SDavid du Colombier gname(char *to, Scan *sp) 109*3e12c5d1SDavid du Colombier { 110*3e12c5d1SDavid du Colombier int len, off; 111*3e12c5d1SDavid du Colombier int pointer; 112*3e12c5d1SDavid du Colombier int n; 113*3e12c5d1SDavid du Colombier char *tostart; 114*3e12c5d1SDavid du Colombier char *toend; 115*3e12c5d1SDavid du Colombier uchar *p; 116*3e12c5d1SDavid du Colombier 117*3e12c5d1SDavid du Colombier tostart = to; 118*3e12c5d1SDavid du Colombier if(sp->err) 119*3e12c5d1SDavid du Colombier goto err; 120*3e12c5d1SDavid du Colombier pointer = 0; 121*3e12c5d1SDavid du Colombier p = sp->p; 122*3e12c5d1SDavid du Colombier toend = to + Domlen; 123*3e12c5d1SDavid du Colombier for(len = 0; *p; len += pointer ? 0 : (n+1)){ 124*3e12c5d1SDavid du Colombier if((*p & 0xc0) == 0xc0){ 125*3e12c5d1SDavid du Colombier /* pointer to other spot in message */ 126*3e12c5d1SDavid du Colombier if(pointer++ > 10){ 127*3e12c5d1SDavid du Colombier sp->err = "pointer loop"; 128*3e12c5d1SDavid du Colombier goto err; 129*3e12c5d1SDavid du Colombier } 130*3e12c5d1SDavid du Colombier off = ((p[0]<<8) + p[1]) & 0x3ff; 131*3e12c5d1SDavid du Colombier p = sp->base + off; 132*3e12c5d1SDavid du Colombier if(p >= sp->ep){ 133*3e12c5d1SDavid du Colombier sp->err = "bad pointer"; 134*3e12c5d1SDavid du Colombier goto err; 135*3e12c5d1SDavid du Colombier } 136*3e12c5d1SDavid du Colombier n = 0; 137*3e12c5d1SDavid du Colombier continue; 138*3e12c5d1SDavid du Colombier } 139*3e12c5d1SDavid du Colombier n = *p++; 140*3e12c5d1SDavid du Colombier if(len + n < Domlen - 1){ 141*3e12c5d1SDavid du Colombier if(to + n > toend){ 142*3e12c5d1SDavid du Colombier sp->err = toolong; 143*3e12c5d1SDavid du Colombier goto err; 144*3e12c5d1SDavid du Colombier } 145*3e12c5d1SDavid du Colombier memmove(to, p, n); 146*3e12c5d1SDavid du Colombier to += n; 147*3e12c5d1SDavid du Colombier } 148*3e12c5d1SDavid du Colombier p += n; 149*3e12c5d1SDavid du Colombier if(*p){ 150*3e12c5d1SDavid du Colombier if(to >= toend){ 151*3e12c5d1SDavid du Colombier sp->err = toolong; 152*3e12c5d1SDavid du Colombier goto err; 153*3e12c5d1SDavid du Colombier } 154*3e12c5d1SDavid du Colombier *to++ = '.'; 155*3e12c5d1SDavid du Colombier } 156*3e12c5d1SDavid du Colombier } 157*3e12c5d1SDavid du Colombier *to = 0; 158*3e12c5d1SDavid du Colombier if(pointer) 159*3e12c5d1SDavid du Colombier sp->p += len + 2; /* + 2 for pointer */ 160*3e12c5d1SDavid du Colombier else 161*3e12c5d1SDavid du Colombier sp->p += len + 1; /* + 1 for the null domain */ 162*3e12c5d1SDavid du Colombier return tostart; 163*3e12c5d1SDavid du Colombier err: 164*3e12c5d1SDavid du Colombier *tostart = 0; 165*3e12c5d1SDavid du Colombier return tostart; 166*3e12c5d1SDavid du Colombier } 167*3e12c5d1SDavid du Colombier 168*3e12c5d1SDavid du Colombier /* 169*3e12c5d1SDavid du Colombier * convert the next RR from a message 170*3e12c5d1SDavid du Colombier */ 171*3e12c5d1SDavid du Colombier static RR* 172*3e12c5d1SDavid du Colombier convM2RR(Scan *sp) 173*3e12c5d1SDavid du Colombier { 174*3e12c5d1SDavid du Colombier RR *rp; 175*3e12c5d1SDavid du Colombier int type; 176*3e12c5d1SDavid du Colombier int class; 177*3e12c5d1SDavid du Colombier uchar *data; 178*3e12c5d1SDavid du Colombier int len; 179*3e12c5d1SDavid du Colombier char dname[Domlen+1]; 180*3e12c5d1SDavid du Colombier 181*3e12c5d1SDavid du Colombier NAME(dname); 182*3e12c5d1SDavid du Colombier USHORT(type); 183*3e12c5d1SDavid du Colombier USHORT(class); 184*3e12c5d1SDavid du Colombier 185*3e12c5d1SDavid du Colombier rp = rralloc(type); 186*3e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 187*3e12c5d1SDavid du Colombier rp->type = type; 188*3e12c5d1SDavid du Colombier 189*3e12c5d1SDavid du Colombier ULONG(rp->ttl); 190*3e12c5d1SDavid du Colombier USHORT(len); 191*3e12c5d1SDavid du Colombier data = sp->p; 192*3e12c5d1SDavid du Colombier switch(type){ 193*3e12c5d1SDavid du Colombier case Thinfo: 194*3e12c5d1SDavid du Colombier STRING(rp->cpu); 195*3e12c5d1SDavid du Colombier STRING(rp->os); 196*3e12c5d1SDavid du Colombier break; 197*3e12c5d1SDavid du Colombier case Tcname: 198*3e12c5d1SDavid du Colombier case Tmb: 199*3e12c5d1SDavid du Colombier case Tmd: 200*3e12c5d1SDavid du Colombier case Tmf: 201*3e12c5d1SDavid du Colombier case Tns: 202*3e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 203*3e12c5d1SDavid du Colombier break; 204*3e12c5d1SDavid du Colombier case Tmg: 205*3e12c5d1SDavid du Colombier case Tmr: 206*3e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 207*3e12c5d1SDavid du Colombier break; 208*3e12c5d1SDavid du Colombier case Tminfo: 209*3e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 210*3e12c5d1SDavid du Colombier rp->mb = dnlookup(NAME(dname), Cin, 1); 211*3e12c5d1SDavid du Colombier break; 212*3e12c5d1SDavid du Colombier case Tmx: 213*3e12c5d1SDavid du Colombier USHORT(rp->pref); 214*3e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 215*3e12c5d1SDavid du Colombier break; 216*3e12c5d1SDavid du Colombier case Ta: 217*3e12c5d1SDavid du Colombier ADDR(rp->ip); 218*3e12c5d1SDavid du Colombier break; 219*3e12c5d1SDavid du Colombier case Tptr: 220*3e12c5d1SDavid du Colombier rp->ptr = dnlookup(NAME(dname), Cin, 1); 221*3e12c5d1SDavid du Colombier break; 222*3e12c5d1SDavid du Colombier case Tsoa: 223*3e12c5d1SDavid du Colombier rp->host = dnlookup(NAME(dname), Cin, 1); 224*3e12c5d1SDavid du Colombier rp->rmb = dnlookup(NAME(dname), Cin, 1); 225*3e12c5d1SDavid du Colombier ULONG(rp->soa->serial); 226*3e12c5d1SDavid du Colombier ULONG(rp->soa->refresh); 227*3e12c5d1SDavid du Colombier ULONG(rp->soa->retry); 228*3e12c5d1SDavid du Colombier ULONG(rp->soa->expire); 229*3e12c5d1SDavid du Colombier ULONG(rp->soa->minttl); 230*3e12c5d1SDavid du Colombier break; 231*3e12c5d1SDavid du Colombier } 232*3e12c5d1SDavid du Colombier if(sp->p - data != len) 233*3e12c5d1SDavid du Colombier sp->err = "bad RR len"; 234*3e12c5d1SDavid du Colombier return rp; 235*3e12c5d1SDavid du Colombier } 236*3e12c5d1SDavid du Colombier 237*3e12c5d1SDavid du Colombier /* 238*3e12c5d1SDavid du Colombier * convert the next question from a message 239*3e12c5d1SDavid du Colombier */ 240*3e12c5d1SDavid du Colombier static RR* 241*3e12c5d1SDavid du Colombier convM2Q(Scan *sp) 242*3e12c5d1SDavid du Colombier { 243*3e12c5d1SDavid du Colombier char dname[Domlen+1]; 244*3e12c5d1SDavid du Colombier int type; 245*3e12c5d1SDavid du Colombier int class; 246*3e12c5d1SDavid du Colombier RR *rp; 247*3e12c5d1SDavid du Colombier 248*3e12c5d1SDavid du Colombier NAME(dname); 249*3e12c5d1SDavid du Colombier USHORT(type); 250*3e12c5d1SDavid du Colombier USHORT(class); 251*3e12c5d1SDavid du Colombier if(sp->err) 252*3e12c5d1SDavid du Colombier return 0; 253*3e12c5d1SDavid du Colombier 254*3e12c5d1SDavid du Colombier rp = rralloc(type); 255*3e12c5d1SDavid du Colombier rp->owner = dnlookup(dname, class, 1); 256*3e12c5d1SDavid du Colombier 257*3e12c5d1SDavid du Colombier return rp; 258*3e12c5d1SDavid du Colombier } 259*3e12c5d1SDavid du Colombier 260*3e12c5d1SDavid du Colombier static RR* 261*3e12c5d1SDavid du Colombier rrloop(Scan *sp, int count, int quest) 262*3e12c5d1SDavid du Colombier { 263*3e12c5d1SDavid du Colombier int i; 264*3e12c5d1SDavid du Colombier static char errbuf[64]; 265*3e12c5d1SDavid du Colombier RR *first, *rp, **l; 266*3e12c5d1SDavid du Colombier 267*3e12c5d1SDavid du Colombier if(sp->err) 268*3e12c5d1SDavid du Colombier return 0; 269*3e12c5d1SDavid du Colombier l = &first; 270*3e12c5d1SDavid du Colombier first = 0; 271*3e12c5d1SDavid du Colombier for(i = 0; i < count; i++){ 272*3e12c5d1SDavid du Colombier rp = quest ? convM2Q(sp) : convM2RR(sp); 273*3e12c5d1SDavid du Colombier if(sp->err){ 274*3e12c5d1SDavid du Colombier rrfree(rp); 275*3e12c5d1SDavid du Colombier break; 276*3e12c5d1SDavid du Colombier } 277*3e12c5d1SDavid du Colombier *l = rp; 278*3e12c5d1SDavid du Colombier l = &rp->next; 279*3e12c5d1SDavid du Colombier } 280*3e12c5d1SDavid du Colombier return first; 281*3e12c5d1SDavid du Colombier } 282*3e12c5d1SDavid du Colombier 283*3e12c5d1SDavid du Colombier /* 284*3e12c5d1SDavid du Colombier * convert the next DNS from a message stream 285*3e12c5d1SDavid du Colombier */ 286*3e12c5d1SDavid du Colombier char* 287*3e12c5d1SDavid du Colombier convM2DNS(uchar *buf, int len, DNSmsg *m) 288*3e12c5d1SDavid du Colombier { 289*3e12c5d1SDavid du Colombier Scan scan; 290*3e12c5d1SDavid du Colombier Scan *sp; 291*3e12c5d1SDavid du Colombier 292*3e12c5d1SDavid du Colombier scan.base = buf; 293*3e12c5d1SDavid du Colombier scan.p = buf; 294*3e12c5d1SDavid du Colombier scan.ep = buf + len; 295*3e12c5d1SDavid du Colombier scan.err = 0; 296*3e12c5d1SDavid du Colombier sp = &scan; 297*3e12c5d1SDavid du Colombier memset(m, 0, sizeof(DNSmsg)); 298*3e12c5d1SDavid du Colombier USHORT(m->id); 299*3e12c5d1SDavid du Colombier USHORT(m->flags); 300*3e12c5d1SDavid du Colombier USHORT(m->qdcount); 301*3e12c5d1SDavid du Colombier USHORT(m->ancount); 302*3e12c5d1SDavid du Colombier USHORT(m->nscount); 303*3e12c5d1SDavid du Colombier USHORT(m->arcount); 304*3e12c5d1SDavid du Colombier m->qd = rrloop(sp, m->qdcount, 1); 305*3e12c5d1SDavid du Colombier m->an = rrloop(sp, m->ancount, 0); 306*3e12c5d1SDavid du Colombier m->ns = rrloop(sp, m->nscount, 0); 307*3e12c5d1SDavid du Colombier m->ar = rrloop(sp, m->arcount, 0); 308*3e12c5d1SDavid du Colombier return scan.err; 309*3e12c5d1SDavid du Colombier } 310