Blob
1 #include <u.h>2 #include <libc.h>3 #include <ip.h>4 #include <bio.h>5 #include <ndb.h>6 #include "dns.h"8 typedef struct Scan Scan;9 struct Scan10 {11 uchar *base;12 uchar *p;13 uchar *ep;14 char *err;15 };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)))27 static char *toolong = "too long";29 /*30 * get a ushort/ulong31 */32 static ushort33 gchar(Scan *sp)34 {35 ushort x;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 ushort48 gshort(Scan *sp)49 {50 ushort x;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 ulong63 glong(Scan *sp)64 {65 ulong x;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 }78 /*79 * get an ip address80 */81 static DN*82 gv4addr(Scan *sp)83 {84 char addr[32];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;95 return dnlookup(addr, Cin, 1);96 }97 static DN*98 gv6addr(Scan *sp)99 {100 char addr[64];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;111 return dnlookup(addr, Cin, 1);112 }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];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 }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;139 return dnlookup(sym, Csym, 1);140 }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;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 }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;168 t = emalloc(sizeof(*t));169 t->next = nil;170 t->p = estrdup(sym);171 return t;172 }174 /*175 * get a sequence of bytes176 */177 static int178 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;190 return n;191 }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;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 else250 sp->p += len + 1; /* + 1 for the null domain */251 return tostart;252 err:253 *tostart = 0;254 return tostart;255 }257 /*258 * convert the next RR from a message259 */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;271 retry:272 NAME(dname);273 USHORT(type);274 USHORT(class);276 rp = rralloc(type);277 rp->owner = dnlookup(dname, class, 1);278 rp->type = type;280 ULONG(rp->ttl);281 rp->ttl += now;282 USHORT(len);283 data = sp->p;285 if(sp->p + len > sp->ep)286 sp->err = toolong;287 if(sp->err){288 rrfree(rp);289 return 0;290 }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 }384 /*385 * convert the next question from a message386 */387 static RR*388 convM2Q(Scan *sp)389 {390 char dname[Domlen+1];391 int type;392 int class;393 RR *rp;395 NAME(dname);396 USHORT(type);397 USHORT(class);398 if(sp->err)399 return 0;401 rp = rralloc(type);402 rp->owner = dnlookup(dname, class, 1);404 return rp;405 }407 static RR*408 rrloop(Scan *sp, int count, int quest)409 {410 int i;411 RR *first, *rp, **l;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 }431 /*432 * convert the next DNS from a message stream433 */434 char*435 convM2DNS(uchar *buf, int len, DNSmsg *m)436 {437 Scan scan;438 Scan *sp;439 char *err;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 }