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