1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include "dns.h" 5 6 typedef struct Scan Scan; 7 struct Scan 8 { 9 uchar *base; 10 uchar *p; 11 uchar *ep; 12 13 char *err; 14 char errbuf[256]; /* hold a formatted error sometimes */ 15 int rcode; /* outgoing response codes (reply flags) */ 16 int stop; /* flag: stop processing */ 17 int trunc; /* flag: input truncated */ 18 }; 19 20 #define NAME(x) gname(x, rp, sp) 21 #define SYMBOL(x) (x = gsym(rp, sp)) 22 #define STRING(x) (x = gstr(rp, sp)) 23 #define USHORT(x) (x = gshort(rp, sp)) 24 #define ULONG(x) (x = glong(rp, sp)) 25 #define UCHAR(x) (x = gchar(rp, sp)) 26 #define V4ADDR(x) (x = gv4addr(rp, sp)) 27 #define V6ADDR(x) (x = gv6addr(rp, sp)) 28 #define BYTES(x, y) (y = gbytes(rp, sp, &x, len - (sp->p - data))) 29 30 static int 31 errneg(RR *rp, Scan *sp, int actual) 32 { 33 snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R", 34 actual, rp); 35 sp->err = sp->errbuf; 36 return 0; 37 } 38 39 static int 40 errtoolong(RR *rp, Scan *sp, int remain, int need, char *where) 41 { 42 char *p, *ep; 43 char ptype[64]; 44 45 p = sp->errbuf; 46 ep = sp->errbuf + sizeof sp->errbuf - 1; 47 if (where) 48 p = seprint(p, ep, "%s: ", where); 49 if (rp) 50 p = seprint(p, ep, "type %s RR: ", 51 rrname(rp->type, ptype, sizeof ptype)); 52 p = seprint(p, ep, "%d bytes needed; %d remain", need, remain); 53 if (rp) 54 seprint(p, ep, ": %R", rp); 55 sp->err = sp->errbuf; 56 /* hack to cope with servers that don't set Ftrunc when they should */ 57 if (remain < Maxudp && need > Maxudp) 58 sp->trunc = 1; 59 return 0; 60 } 61 62 /* 63 * get a ushort/ulong 64 */ 65 static ushort 66 gchar(RR *rp, Scan *sp) 67 { 68 ushort x; 69 70 if(sp->err) 71 return 0; 72 if(sp->ep - sp->p < 1) 73 return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar"); 74 x = sp->p[0]; 75 sp->p += 1; 76 return x; 77 } 78 static ushort 79 gshort(RR *rp, Scan *sp) 80 { 81 ushort x; 82 83 if(sp->err) 84 return 0; 85 if(sp->ep - sp->p < 2) 86 return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort"); 87 x = sp->p[0]<<8 | sp->p[1]; 88 sp->p += 2; 89 return x; 90 } 91 static ulong 92 glong(RR *rp, Scan *sp) 93 { 94 ulong x; 95 96 if(sp->err) 97 return 0; 98 if(sp->ep - sp->p < 4) 99 return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong"); 100 x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3]; 101 sp->p += 4; 102 return x; 103 } 104 105 /* 106 * get an ip address 107 */ 108 static DN* 109 gv4addr(RR *rp, Scan *sp) 110 { 111 char addr[32]; 112 113 if(sp->err) 114 return 0; 115 if(sp->ep - sp->p < 4) 116 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr"); 117 snprint(addr, sizeof addr, "%V", sp->p); 118 sp->p += 4; 119 120 return dnlookup(addr, Cin, 1); 121 } 122 static DN* 123 gv6addr(RR *rp, Scan *sp) 124 { 125 char addr[64]; 126 127 if(sp->err) 128 return 0; 129 if(sp->ep - sp->p < IPaddrlen) 130 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen, 131 "gv6addr"); 132 snprint(addr, sizeof addr, "%I", sp->p); 133 sp->p += IPaddrlen; 134 135 return dnlookup(addr, Cin, 1); 136 } 137 138 /* 139 * get a string. make it an internal symbol. 140 */ 141 static DN* 142 gsym(RR *rp, Scan *sp) 143 { 144 int n; 145 char sym[Strlen+1]; 146 147 if(sp->err) 148 return 0; 149 n = 0; 150 if (sp->p < sp->ep) 151 n = *(sp->p++); 152 if(sp->ep - sp->p < n) 153 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym"); 154 155 if(n > Strlen){ 156 sp->err = "illegal string (symbol)"; 157 return 0; 158 } 159 strncpy(sym, (char*)sp->p, n); 160 sym[n] = 0; 161 if (strlen(sym) != n) 162 sp->err = "symbol shorter than declared length"; 163 sp->p += n; 164 165 return dnlookup(sym, Csym, 1); 166 } 167 168 /* 169 * get a string. don't make it an internal symbol. 170 */ 171 static Txt* 172 gstr(RR *rp, Scan *sp) 173 { 174 int n; 175 char sym[Strlen+1]; 176 Txt *t; 177 178 if(sp->err) 179 return 0; 180 n = 0; 181 if (sp->p < sp->ep) 182 n = *(sp->p++); 183 if(sp->ep - sp->p < n) 184 return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr"); 185 186 if(n > Strlen){ 187 sp->err = "illegal string"; 188 return 0; 189 } 190 strncpy(sym, (char*)sp->p, n); 191 sym[n] = 0; 192 if (strlen(sym) != n) 193 sp->err = "string shorter than declared length"; 194 sp->p += n; 195 196 t = emalloc(sizeof(*t)); 197 t->next = nil; 198 t->p = estrdup(sym); 199 return t; 200 } 201 202 /* 203 * get a sequence of bytes 204 */ 205 static int 206 gbytes(RR *rp, Scan *sp, uchar **p, int n) 207 { 208 *p = nil; /* i think this is a good idea */ 209 if(sp->err) 210 return 0; 211 if(n < 0) 212 return errneg(rp, sp, n); 213 if(sp->ep - sp->p < n) 214 return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes"); 215 *p = emalloc(n); 216 memmove(*p, sp->p, n); 217 sp->p += n; 218 219 return n; 220 } 221 222 /* 223 * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 224 */ 225 static char* 226 gname(char *to, RR *rp, Scan *sp) 227 { 228 int len, off, pointer, n; 229 char *tostart, *toend; 230 uchar *p; 231 232 tostart = to; 233 if(sp->err || sp->stop) 234 goto err; 235 pointer = 0; 236 p = sp->p; 237 toend = to + Domlen; 238 for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) { 239 n = 0; 240 switch (*p & 0300) { 241 case 0: /* normal label */ 242 if (p < sp->ep) 243 n = *p++ & 077; /* pick up length */ 244 if(len + n < Domlen - 1){ 245 if(n > toend - to){ 246 errtoolong(rp, sp, toend - to, n, 247 "name too long"); 248 goto err; 249 } 250 memmove(to, p, n); 251 to += n; 252 } 253 p += n; 254 if(*p){ 255 if(to >= toend){ 256 errtoolong(rp, sp, toend - to, 2, 257 "more name components but no bytes left"); 258 goto err; 259 } 260 *to++ = '.'; 261 } 262 break; 263 case 0100: /* edns extended label type, rfc 2671 */ 264 /* 265 * treat it like an EOF for now; it seems to be at 266 * the end of a long tcp reply. 267 */ 268 dnslog("edns label; first byte 0%o = '%c'", *p, *p); 269 sp->stop = 1; 270 goto err; 271 case 0200: /* reserved */ 272 sp->err = "reserved-use label present"; 273 goto err; 274 case 0300: /* pointer to other spot in message */ 275 if(pointer++ > 10){ 276 sp->err = "pointer loop"; 277 goto err; 278 } 279 off = (p[0] & 077)<<8 | p[1]; 280 p = sp->base + off; 281 if(p >= sp->ep){ 282 sp->err = "bad pointer"; 283 goto err; 284 } 285 n = 0; 286 break; 287 } 288 } 289 *to = 0; 290 if(pointer) 291 sp->p += len + 2; /* + 2 for pointer */ 292 else 293 sp->p += len + 1; /* + 1 for the null domain */ 294 return tostart; 295 err: 296 *tostart = 0; 297 return tostart; 298 } 299 300 /* 301 * ms windows 2000 seems to get the bytes backward in the type field 302 * of ptr records, so return a format error as feedback. 303 */ 304 static void 305 mstypehack(Scan *sp, int type, char *where) 306 { 307 if ((uchar)type == 0 && (uchar)(type>>8) != 0) { 308 USED(where); 309 // dnslog("%s: byte-swapped type field in ptr rr from win2k", 310 // where); 311 if (sp->rcode == 0) 312 sp->rcode = Rformat; 313 } 314 } 315 316 /* 317 * convert the next RR from a message 318 */ 319 static RR* 320 convM2RR(Scan *sp, char *what) 321 { 322 int type, class, len; 323 char dname[Domlen+1]; 324 uchar *data; 325 RR *rp = nil; 326 Txt *t, **l; 327 328 retry: 329 NAME(dname); 330 USHORT(type); 331 USHORT(class); 332 333 mstypehack(sp, type, "convM2RR"); 334 rp = rralloc(type); 335 rp->owner = dnlookup(dname, class, 1); 336 rp->type = type; 337 338 ULONG(rp->ttl); 339 rp->ttl += now; 340 USHORT(len); 341 data = sp->p; 342 343 /* 344 * ms windows generates a lot of badly-formatted hints. 345 * hints are only advisory, so don't log complaints about them. 346 * it also generates answers in which p overshoots ep by exactly 347 * one byte; this seems to be harmless, so don't log them either. 348 */ 349 if (sp->ep - sp->p < len && 350 !(strcmp(what, "hints") == 0 || 351 sp->p == sp->ep + 1 && strcmp(what, "answers") == 0)) 352 errtoolong(rp, sp, sp->ep - sp->p, len, "convM2RR"); 353 if(sp->err || sp->rcode || sp->stop){ 354 rrfree(rp); 355 return nil; 356 } 357 358 switch(type){ 359 default: 360 /* unknown type, just ignore it */ 361 sp->p = data + len; 362 rrfree(rp); 363 rp = nil; 364 goto retry; 365 case Thinfo: 366 SYMBOL(rp->cpu); 367 SYMBOL(rp->os); 368 break; 369 case Tcname: 370 case Tmb: 371 case Tmd: 372 case Tmf: 373 case Tns: 374 rp->host = dnlookup(NAME(dname), Cin, 1); 375 break; 376 case Tmg: 377 case Tmr: 378 rp->mb = dnlookup(NAME(dname), Cin, 1); 379 break; 380 case Tminfo: 381 rp->rmb = dnlookup(NAME(dname), Cin, 1); 382 rp->mb = dnlookup(NAME(dname), Cin, 1); 383 break; 384 case Tmx: 385 USHORT(rp->pref); 386 rp->host = dnlookup(NAME(dname), Cin, 1); 387 break; 388 case Ta: 389 V4ADDR(rp->ip); 390 break; 391 case Taaaa: 392 V6ADDR(rp->ip); 393 break; 394 case Tptr: 395 rp->ptr = dnlookup(NAME(dname), Cin, 1); 396 break; 397 case Tsoa: 398 rp->host = dnlookup(NAME(dname), Cin, 1); 399 rp->rmb = dnlookup(NAME(dname), Cin, 1); 400 ULONG(rp->soa->serial); 401 ULONG(rp->soa->refresh); 402 ULONG(rp->soa->retry); 403 ULONG(rp->soa->expire); 404 ULONG(rp->soa->minttl); 405 break; 406 case Tsrv: 407 USHORT(rp->srv->pri); 408 USHORT(rp->srv->weight); 409 USHORT(rp->srv->port); 410 rp->srv->target = dnlookup(NAME(dname), Cin, 1); 411 break; 412 case Ttxt: 413 l = &rp->txt; 414 *l = nil; 415 while(sp->p - data < len){ 416 STRING(t); 417 *l = t; 418 l = &t->next; 419 } 420 break; 421 case Tnull: 422 BYTES(rp->null->data, rp->null->dlen); 423 break; 424 case Trp: 425 rp->rmb = dnlookup(NAME(dname), Cin, 1); 426 rp->rp = dnlookup(NAME(dname), Cin, 1); 427 break; 428 case Tkey: 429 USHORT(rp->key->flags); 430 UCHAR(rp->key->proto); 431 UCHAR(rp->key->alg); 432 BYTES(rp->key->data, rp->key->dlen); 433 break; 434 case Tsig: 435 USHORT(rp->sig->type); 436 UCHAR(rp->sig->alg); 437 UCHAR(rp->sig->labels); 438 ULONG(rp->sig->ttl); 439 ULONG(rp->sig->exp); 440 ULONG(rp->sig->incep); 441 USHORT(rp->sig->tag); 442 rp->sig->signer = dnlookup(NAME(dname), Cin, 1); 443 BYTES(rp->sig->data, rp->sig->dlen); 444 break; 445 case Tcert: 446 USHORT(rp->cert->type); 447 USHORT(rp->cert->tag); 448 UCHAR(rp->cert->alg); 449 BYTES(rp->cert->data, rp->cert->dlen); 450 break; 451 } 452 if(sp->p - data != len) { 453 char ptype[64]; 454 455 /* 456 * ms windows 2000 generates cname queries for reverse lookups 457 * with this particular error. don't bother logging it. 458 * 459 * server: input error: bad cname RR len (actual 2 != len 0): 460 * 235.9.104.135.in-addr.arpa cname 461 * 235.9.104.135.in-addr.arpa from 135.104.9.235 462 */ 463 if (type == Tcname && sp->p - data == 2 && len == 0) { 464 // dnslog("convM2RR: got %R", rp); 465 return rp; 466 } 467 if (len > sp->p - data) 468 dnslog("bad %s RR len (%d bytes nominal, %lud actual): %R", 469 rrname(type, ptype, sizeof ptype), len, 470 sp->p - data, rp); 471 // sp->p = data + len; 472 } 473 // dnslog("convM2RR: got %R", rp); 474 return rp; 475 } 476 477 /* 478 * convert the next question from a message 479 */ 480 static RR* 481 convM2Q(Scan *sp) 482 { 483 char dname[Domlen+1]; 484 int type, class; 485 RR *rp = nil; 486 487 NAME(dname); 488 USHORT(type); 489 USHORT(class); 490 if(sp->err || sp->rcode || sp->stop) 491 return nil; 492 493 mstypehack(sp, type, "convM2Q"); 494 rp = rralloc(type); 495 rp->owner = dnlookup(dname, class, 1); 496 497 return rp; 498 } 499 500 static RR* 501 rrloop(Scan *sp, char *what, int count, int quest) 502 { 503 int i; 504 RR *first, *rp, **l; 505 506 if(sp->err || sp->rcode || sp->stop) 507 return nil; 508 l = &first; 509 first = nil; 510 for(i = 0; i < count; i++){ 511 rp = quest? convM2Q(sp): convM2RR(sp, what); 512 if(rp == nil) 513 break; 514 setmalloctag(rp, getcallerpc(&sp)); 515 if(sp->err || sp->rcode || sp->stop){ 516 rrfree(rp); 517 break; 518 } 519 *l = rp; 520 l = &rp->next; 521 } 522 // setmalloctag(first, getcallerpc(&sp)); 523 return first; 524 } 525 526 /* 527 * convert the next DNS from a message stream. 528 * if there are formatting errors or the like during parsing of the message, 529 * set *codep to the outgoing response code (e.g., Rformat), which will 530 * abort processing and reply immediately with the outgoing response code. 531 */ 532 char* 533 convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep) 534 { 535 char *err = nil; 536 RR *rp = nil; 537 Scan scan; 538 Scan *sp; 539 540 if (codep) 541 *codep = 0; 542 assert(len >= 0); 543 sp = &scan; 544 memset(sp, 0, sizeof *sp); 545 sp->base = sp->p = buf; 546 sp->ep = buf + len; 547 sp->err = nil; 548 sp->errbuf[0] = '\0'; 549 550 memset(m, 0, sizeof *m); 551 USHORT(m->id); 552 USHORT(m->flags); 553 USHORT(m->qdcount); 554 USHORT(m->ancount); 555 USHORT(m->nscount); 556 USHORT(m->arcount); 557 558 m->qd = rrloop(sp, "questions", m->qdcount, 1); 559 m->an = rrloop(sp, "answers", m->ancount, 0); 560 m->ns = rrloop(sp, "nameservers",m->nscount, 0); 561 if (sp->stop) 562 sp->err = nil; 563 if (sp->err) 564 err = strdup(sp->err); /* live with bad ar's */ 565 m->ar = rrloop(sp, "hints", m->arcount, 0); 566 if (sp->trunc) 567 m->flags |= Ftrunc; 568 if (sp->stop) 569 sp->rcode = 0; 570 if (codep) 571 *codep = sp->rcode; 572 return err; 573 } 574