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 char *err; 13 }; 14 15 #define NAME(x) gname(x, sp) 16 #define SYMBOL(x) (x = gsym(sp)) 17 #define STRING(x) (x = gstr(sp)) 18 #define USHORT(x) (x = gshort(sp)) 19 #define ULONG(x) (x = glong(sp)) 20 #define UCHAR(x) (x = gchar(sp)) 21 #define V4ADDR(x) (x = gv4addr(sp)) 22 #define V6ADDR(x) (x = gv6addr(sp)) 23 #define BYTES(x, y) (y = gbytes(sp, &x, len - (sp->p - data))) 24 25 static char *toolong = "too long"; 26 27 /* 28 * get a ushort/ulong 29 */ 30 static ushort 31 gchar(Scan *sp) 32 { 33 ushort x; 34 35 if(sp->err) 36 return 0; 37 if(sp->ep - sp->p < 1){ 38 sp->err = toolong; 39 return 0; 40 } 41 x = sp->p[0]; 42 sp->p += 1; 43 return x; 44 } 45 static ushort 46 gshort(Scan *sp) 47 { 48 ushort x; 49 50 if(sp->err) 51 return 0; 52 if(sp->ep - sp->p < 2){ 53 sp->err = toolong; 54 return 0; 55 } 56 x = (sp->p[0]<<8) | sp->p[1]; 57 sp->p += 2; 58 return x; 59 } 60 static ulong 61 glong(Scan *sp) 62 { 63 ulong x; 64 65 if(sp->err) 66 return 0; 67 if(sp->ep - sp->p < 4){ 68 sp->err = toolong; 69 return 0; 70 } 71 x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3]; 72 sp->p += 4; 73 return x; 74 } 75 76 /* 77 * get an ip address 78 */ 79 static DN* 80 gv4addr(Scan *sp) 81 { 82 char addr[32]; 83 84 if(sp->err) 85 return 0; 86 if(sp->ep - sp->p < 4){ 87 sp->err = toolong; 88 return 0; 89 } 90 snprint(addr, sizeof(addr), "%V", sp->p); 91 sp->p += 4; 92 93 return dnlookup(addr, Cin, 1); 94 } 95 static DN* 96 gv6addr(Scan *sp) 97 { 98 char addr[64]; 99 100 if(sp->err) 101 return 0; 102 if(sp->ep - sp->p < IPaddrlen){ 103 sp->err = toolong; 104 return 0; 105 } 106 snprint(addr, sizeof(addr), "%I", sp->p); 107 sp->p += IPaddrlen; 108 109 return dnlookup(addr, Cin, 1); 110 } 111 112 /* 113 * get a string. make it an internal symbol. 114 */ 115 static DN* 116 gsym(Scan *sp) 117 { 118 int n; 119 char sym[Strlen+1]; 120 121 if(sp->err) 122 return 0; 123 n = *(sp->p++); 124 if(sp->p+n > sp->ep){ 125 sp->err = toolong; 126 return 0; 127 } 128 129 if(n > Strlen){ 130 sp->err = "illegal string"; 131 return 0; 132 } 133 strncpy(sym, (char*)sp->p, n); 134 sym[n] = 0; 135 sp->p += n; 136 137 return dnlookup(sym, Csym, 1); 138 } 139 140 /* 141 * get a string. don't make it an internal symbol. 142 */ 143 static Txt* 144 gstr(Scan *sp) 145 { 146 int n; 147 char sym[Strlen+1]; 148 Txt *t; 149 150 if(sp->err) 151 return 0; 152 n = *(sp->p++); 153 if(sp->p+n > sp->ep){ 154 sp->err = toolong; 155 return 0; 156 } 157 158 if(n > Strlen){ 159 sp->err = "illegal string"; 160 return 0; 161 } 162 strncpy(sym, (char*)sp->p, n); 163 sym[n] = 0; 164 sp->p += n; 165 166 t = emalloc(sizeof(*t)); 167 t->next = nil; 168 t->p = estrdup(sym); 169 return t; 170 } 171 172 /* 173 * get a sequence of bytes 174 */ 175 static int 176 gbytes(Scan *sp, uchar **p, int n) 177 { 178 if(sp->err) 179 return 0; 180 if(sp->p+n > sp->ep || n < 0){ 181 sp->err = toolong; 182 return 0; 183 } 184 *p = emalloc(n); 185 memmove(*p, sp->p, n); 186 sp->p += n; 187 188 return n; 189 } 190 191 /* 192 * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 193 */ 194 static char* 195 gname(char *to, Scan *sp) 196 { 197 int len, off; 198 int pointer; 199 int n; 200 char *tostart; 201 char *toend; 202 uchar *p; 203 204 tostart = to; 205 if(sp->err) 206 goto err; 207 pointer = 0; 208 p = sp->p; 209 toend = to + Domlen; 210 for(len = 0; *p; len += pointer ? 0 : (n+1)){ 211 if((*p & 0xc0) == 0xc0){ 212 /* pointer to other spot in message */ 213 if(pointer++ > 10){ 214 sp->err = "pointer loop"; 215 goto err; 216 } 217 off = ((p[0]<<8) + p[1]) & 0x3ff; 218 p = sp->base + off; 219 if(p >= sp->ep){ 220 sp->err = "bad pointer"; 221 goto err; 222 } 223 n = 0; 224 continue; 225 } 226 n = *p++; 227 if(len + n < Domlen - 1){ 228 if(to + n > toend){ 229 sp->err = toolong; 230 goto err; 231 } 232 memmove(to, p, n); 233 to += n; 234 } 235 p += n; 236 if(*p){ 237 if(to >= toend){ 238 sp->err = toolong; 239 goto err; 240 } 241 *to++ = '.'; 242 } 243 } 244 *to = 0; 245 if(pointer) 246 sp->p += len + 2; /* + 2 for pointer */ 247 else 248 sp->p += len + 1; /* + 1 for the null domain */ 249 return tostart; 250 err: 251 *tostart = 0; 252 return tostart; 253 } 254 255 /* 256 * convert the next RR from a message 257 */ 258 static RR* 259 convM2RR(Scan *sp) 260 { 261 RR *rp; 262 int type; 263 int class; 264 uchar *data; 265 int len; 266 char dname[Domlen+1]; 267 Txt *t, **l; 268 269 retry: 270 NAME(dname); 271 USHORT(type); 272 USHORT(class); 273 274 rp = rralloc(type); 275 rp->owner = dnlookup(dname, class, 1); 276 rp->type = type; 277 278 ULONG(rp->ttl); 279 rp->ttl += now; 280 USHORT(len); 281 data = sp->p; 282 283 if(sp->p + len > sp->ep) 284 sp->err = toolong; 285 if(sp->err){ 286 rrfree(rp); 287 return 0; 288 } 289 290 switch(type){ 291 default: 292 /* unknown type, just ignore it */ 293 sp->p = data + len; 294 rrfree(rp); 295 goto retry; 296 case Thinfo: 297 SYMBOL(rp->cpu); 298 SYMBOL(rp->os); 299 break; 300 case Tcname: 301 case Tmb: 302 case Tmd: 303 case Tmf: 304 case Tns: 305 rp->host = dnlookup(NAME(dname), Cin, 1); 306 break; 307 case Tmg: 308 case Tmr: 309 rp->mb = dnlookup(NAME(dname), Cin, 1); 310 break; 311 case Tminfo: 312 rp->rmb = dnlookup(NAME(dname), Cin, 1); 313 rp->mb = dnlookup(NAME(dname), Cin, 1); 314 break; 315 case Tmx: 316 USHORT(rp->pref); 317 rp->host = dnlookup(NAME(dname), Cin, 1); 318 break; 319 case Ta: 320 V4ADDR(rp->ip); 321 break; 322 case Taaaa: 323 V6ADDR(rp->ip); 324 break; 325 case Tptr: 326 rp->ptr = dnlookup(NAME(dname), Cin, 1); 327 break; 328 case Tsoa: 329 rp->host = dnlookup(NAME(dname), Cin, 1); 330 rp->rmb = dnlookup(NAME(dname), Cin, 1); 331 ULONG(rp->soa->serial); 332 ULONG(rp->soa->refresh); 333 ULONG(rp->soa->retry); 334 ULONG(rp->soa->expire); 335 ULONG(rp->soa->minttl); 336 break; 337 case Ttxt: 338 l = &rp->txt; 339 *l = nil; 340 while(sp->p-data < len){ 341 STRING(t); 342 *l = t; 343 l = &t->next; 344 } 345 break; 346 case Tnull: 347 BYTES(rp->null->data, rp->null->dlen); 348 break; 349 case Trp: 350 rp->rmb = dnlookup(NAME(dname), Cin, 1); 351 rp->rp = dnlookup(NAME(dname), Cin, 1); 352 break; 353 case Tkey: 354 USHORT(rp->key->flags); 355 UCHAR(rp->key->proto); 356 UCHAR(rp->key->alg); 357 BYTES(rp->key->data, rp->key->dlen); 358 break; 359 case Tsig: 360 USHORT(rp->sig->type); 361 UCHAR(rp->sig->alg); 362 UCHAR(rp->sig->labels); 363 ULONG(rp->sig->ttl); 364 ULONG(rp->sig->exp); 365 ULONG(rp->sig->incep); 366 USHORT(rp->sig->tag); 367 rp->sig->signer = dnlookup(NAME(dname), Cin, 1); 368 BYTES(rp->sig->data, rp->sig->dlen); 369 break; 370 case Tcert: 371 USHORT(rp->cert->type); 372 USHORT(rp->cert->tag); 373 UCHAR(rp->cert->alg); 374 BYTES(rp->cert->data, rp->cert->dlen); 375 break; 376 } 377 if(sp->p - data != len) 378 sp->err = "bad RR len"; 379 return rp; 380 } 381 382 /* 383 * convert the next question from a message 384 */ 385 static RR* 386 convM2Q(Scan *sp) 387 { 388 char dname[Domlen+1]; 389 int type; 390 int class; 391 RR *rp; 392 393 NAME(dname); 394 USHORT(type); 395 USHORT(class); 396 if(sp->err) 397 return 0; 398 399 rp = rralloc(type); 400 rp->owner = dnlookup(dname, class, 1); 401 402 return rp; 403 } 404 405 static RR* 406 rrloop(Scan *sp, int count, int quest) 407 { 408 int i; 409 static char errbuf[64]; 410 RR *first, *rp, **l; 411 412 if(sp->err) 413 return 0; 414 l = &first; 415 first = 0; 416 for(i = 0; i < count; i++){ 417 rp = quest ? convM2Q(sp) : convM2RR(sp); 418 if(rp == 0) 419 break; 420 if(sp->err){ 421 rrfree(rp); 422 break; 423 } 424 *l = rp; 425 l = &rp->next; 426 } 427 return first; 428 } 429 430 /* 431 * convert the next DNS from a message stream 432 */ 433 char* 434 convM2DNS(uchar *buf, int len, DNSmsg *m) 435 { 436 Scan scan; 437 Scan *sp; 438 char *err; 439 440 scan.base = buf; 441 scan.p = buf; 442 scan.ep = buf + len; 443 scan.err = 0; 444 sp = &scan; 445 memset(m, 0, sizeof(DNSmsg)); 446 USHORT(m->id); 447 USHORT(m->flags); 448 USHORT(m->qdcount); 449 USHORT(m->ancount); 450 USHORT(m->nscount); 451 USHORT(m->arcount); 452 m->qd = rrloop(sp, m->qdcount, 1); 453 m->an = rrloop(sp, m->ancount, 0); 454 m->ns = rrloop(sp, m->nscount, 0); 455 err = scan.err; /* live with bad ar's */ 456 m->ar = rrloop(sp, m->arcount, 0); 457 return err; 458 } 459