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