6 typedef struct Scan Scan;
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 */
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)))
31 errneg(RR *rp, Scan *sp, int actual)
33 snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R",
40 errtoolong(RR *rp, Scan *sp, int remain, int need, char *where)
46 ep = sp->errbuf + sizeof sp->errbuf - 1;
48 p = seprint(p, ep, "%s: ", where);
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);
54 seprint(p, ep, ": %R", rp);
56 /* hack to cope with servers that don't set Ftrunc when they should */
57 if (remain < Maxudp && need > Maxudp)
60 dnslog("malformed rr: %R", rp);
68 gchar(RR *rp, Scan *sp)
74 if(sp->ep - sp->p < 1)
75 return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar");
81 gshort(RR *rp, Scan *sp)
87 if(sp->ep - sp->p < 2)
88 return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort");
89 x = sp->p[0]<<8 | sp->p[1];
94 glong(RR *rp, Scan *sp)
100 if(sp->ep - sp->p < 4)
101 return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong");
102 x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3];
111 gv4addr(RR *rp, Scan *sp)
117 if(sp->ep - sp->p < 4)
118 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
119 snprint(addr, sizeof addr, "%V", sp->p);
122 return dnlookup(addr, Cin, 1);
125 gv6addr(RR *rp, Scan *sp)
131 if(sp->ep - sp->p < IPaddrlen)
132 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
134 snprint(addr, sizeof addr, "%I", sp->p);
137 return dnlookup(addr, Cin, 1);
141 * get a string. make it an internal symbol.
144 gsym(RR *rp, Scan *sp)
154 if(sp->ep - sp->p < n)
155 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
158 sp->err = "illegal string (symbol)";
161 strncpy(sym, (char*)sp->p, n);
163 if (strlen(sym) != n)
164 sp->err = "symbol shorter than declared length";
167 return dnlookup(sym, Csym, 1);
171 * get a string. don't make it an internal symbol.
174 gstr(RR *rp, Scan *sp)
185 if(sp->ep - sp->p < n)
186 return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
189 sp->err = "illegal string";
192 strncpy(sym, (char*)sp->p, n);
194 if (strlen(sym) != n)
195 sp->err = "string shorter than declared length";
198 t = emalloc(sizeof(*t));
205 * get a sequence of bytes
208 gbytes(RR *rp, Scan *sp, uchar **p, int n)
210 *p = nil; /* i think this is a good idea */
214 return errneg(rp, sp, n);
215 if(sp->ep - sp->p < n)
216 return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes");
218 memmove(*p, sp->p, n);
225 * get a domain name. 'to' must point to a buffer at least Domlen+1 long.
228 gname(char *to, RR *rp, Scan *sp)
230 int len, off, pointer, n;
231 char *tostart, *toend;
235 if(sp->err || sp->stop)
240 for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) {
243 case 0: /* normal label */
245 n = *p++ & 077; /* pick up length */
246 if(len + n < Domlen - 1){
248 errtoolong(rp, sp, toend - to, n,
258 errtoolong(rp, sp, toend - to, 2,
259 "more name components but no bytes left");
265 case 0100: /* edns extended label type, rfc 2671 */
267 * treat it like an EOF for now; it seems to be at
268 * the end of a long tcp reply.
270 dnslog("edns label; first byte 0%o = '%c'", *p, *p);
273 case 0200: /* reserved */
274 sp->err = "reserved-use label present";
276 case 0300: /* pointer to other spot in message */
278 sp->err = "pointer loop";
281 off = (p[0] & 077)<<8 | p[1];
284 sp->err = "bad pointer";
293 sp->p += len + 2; /* + 2 for pointer */
295 sp->p += len + 1; /* + 1 for the null domain */
303 * ms windows 2000 seems to get the bytes backward in the type field
304 * of ptr records, so return a format error as feedback.
307 mstypehack(Scan *sp, ushort type, char *where)
309 if ((uchar)type == 0 && (type>>8) != 0) {
311 // dnslog("%s: byte-swapped type field in ptr rr from win2k",
313 if (sp->rcode == Rok)
315 return (uchar)type << 8 | type >> 8;
321 * convert the next RR from a message
324 convM2RR(Scan *sp, char *what)
326 int type, class, len;
327 char dname[Domlen+1];
337 type = mstypehack(sp, type, "convM2RR");
339 rp->owner = dnlookup(dname, class, 1);
348 * ms windows generates a lot of badly-formatted hints.
349 * hints are only advisory, so don't log complaints about them.
350 * it also generates answers in which p overshoots ep by exactly
351 * one byte; this seems to be harmless, so don't log them either.
353 if (sp->ep - sp->p < len &&
354 !(strcmp(what, "hints") == 0 ||
355 sp->p == sp->ep + 1 && strcmp(what, "answers") == 0))
356 errtoolong(rp, sp, sp->ep - sp->p, len, "convM2RR");
357 if(sp->err || sp->rcode || sp->stop){
364 /* unknown type, just ignore it */
378 rp->host = dnlookup(NAME(dname), Cin, 1);
382 rp->mb = dnlookup(NAME(dname), Cin, 1);
385 rp->rmb = dnlookup(NAME(dname), Cin, 1);
386 rp->mb = dnlookup(NAME(dname), Cin, 1);
390 rp->host = dnlookup(NAME(dname), Cin, 1);
399 rp->ptr = dnlookup(NAME(dname), Cin, 1);
402 rp->host = dnlookup(NAME(dname), Cin, 1);
403 rp->rmb = dnlookup(NAME(dname), Cin, 1);
404 ULONG(rp->soa->serial);
405 ULONG(rp->soa->refresh);
406 ULONG(rp->soa->retry);
407 ULONG(rp->soa->expire);
408 ULONG(rp->soa->minttl);
411 USHORT(rp->srv->pri);
412 USHORT(rp->srv->weight);
415 * rfc2782 sez no name compression but to be
416 * backward-compatible with rfc2052, we try to expand the name.
417 * if the length is under 64 bytes, either interpretation is
418 * fine; if it's longer, we'll assume it's compressed,
419 * as recommended by rfc3597.
421 rp->host = dnlookup(NAME(dname), Cin, 1);
426 while(sp->p - data < len){
433 BYTES(rp->null->data, rp->null->dlen);
436 rp->rmb = dnlookup(NAME(dname), Cin, 1);
437 rp->rp = dnlookup(NAME(dname), Cin, 1);
440 USHORT(rp->key->flags);
441 UCHAR(rp->key->proto);
443 BYTES(rp->key->data, rp->key->dlen);
446 USHORT(rp->sig->type);
448 UCHAR(rp->sig->labels);
451 ULONG(rp->sig->incep);
452 USHORT(rp->sig->tag);
453 rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
454 BYTES(rp->sig->data, rp->sig->dlen);
457 USHORT(rp->cert->type);
458 USHORT(rp->cert->tag);
459 UCHAR(rp->cert->alg);
460 BYTES(rp->cert->data, rp->cert->dlen);
463 if(sp->p - data != len) {
467 * ms windows 2000 generates cname queries for reverse lookups
468 * with this particular error. don't bother logging it.
470 * server: input error: bad cname RR len (actual 2 != len 0):
471 * 235.9.104.135.in-addr.arpa cname
472 * 235.9.104.135.in-addr.arpa from 135.104.9.235
474 if (type == Tcname && sp->p - data == 2 && len == 0)
476 if (len > sp->p - data){
477 dnslog("bad %s RR len (%d bytes nominal, %lud actual): %R",
478 rrname(type, ptype, sizeof ptype), len,
484 // if(rp) dnslog("convM2RR: got %R", rp);
489 * convert the next question from a message
494 char dname[Domlen+1];
501 if(sp->err || sp->rcode || sp->stop)
504 type = mstypehack(sp, type, "convM2Q");
506 rp->owner = dnlookup(dname, class, 1);
512 rrloop(Scan *sp, char *what, int count, int quest)
517 if(sp->err || sp->rcode || sp->stop)
521 for(i = 0; i < count; i++){
522 rp = quest? convM2Q(sp): convM2RR(sp, what);
525 setmalloctag(rp, getcallerpc(&sp));
527 * it might be better to ignore the bad rr, possibly break out,
528 * but return the previous rrs, if any. that way our callers
529 * would know that they had got a response, however ill-formed.
531 if(sp->err || sp->rcode || sp->stop){
538 // setmalloctag(first, getcallerpc(&sp));
543 * convert the next DNS from a message stream.
544 * if there are formatting errors or the like during parsing of the message,
545 * set *codep to the outgoing response code (e.g., Rformat), which will
546 * abort processing and reply immediately with the outgoing response code.
549 convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep)
560 memset(sp, 0, sizeof *sp);
561 sp->base = sp->p = buf;
564 sp->errbuf[0] = '\0';
566 memset(m, 0, sizeof *m);
574 m->qd = rrloop(sp, "questions", m->qdcount, 1);
575 m->an = rrloop(sp, "answers", m->ancount, 0);
576 m->ns = rrloop(sp, "nameservers",m->nscount, 0);
580 err = strdup(sp->err); /* live with bad ar's */
581 m->ar = rrloop(sp, "hints", m->arcount, 0);