6 typedef struct Scan Scan;
9 uchar *base; /* input buffer */
10 uchar *p; /* current position */
11 uchar *ep; /* byte after the end */
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 */
21 errneg(RR *rp, Scan *sp, int actual)
23 snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R",
30 errtoolong(RR *rp, Scan *sp, int remain, int need, char *where)
36 ep = sp->errbuf + sizeof sp->errbuf - 1;
38 p = seprint(p, ep, "%s: ", where);
40 p = seprint(p, ep, "type %s RR: ",
41 rrname(rp->type, ptype, sizeof ptype));
42 p = seprint(p, ep, "%d bytes needed; %d remain", need, remain);
44 seprint(p, ep, ": %R", rp);
46 /* hack to cope with servers that don't set Ftrunc when they should */
47 if (remain < Maxudp && need > Maxudp)
50 dnslog("malformed rr: %R", rp);
58 gchar(RR *rp, Scan *sp)
64 if(sp->ep - sp->p < 1)
65 return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar");
71 gshort(RR *rp, Scan *sp)
77 if(sp->ep - sp->p < 2)
78 return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort");
79 x = sp->p[0]<<8 | sp->p[1];
84 glong(RR *rp, Scan *sp)
90 if(sp->ep - sp->p < 4)
91 return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong");
92 x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3];
101 gv4addr(RR *rp, Scan *sp)
107 if(sp->ep - sp->p < 4)
108 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
109 snprint(addr, sizeof addr, "%V", sp->p);
112 return dnlookup(addr, Cin, 1);
115 gv6addr(RR *rp, Scan *sp)
121 if(sp->ep - sp->p < IPaddrlen)
122 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
124 snprint(addr, sizeof addr, "%I", sp->p);
127 return dnlookup(addr, Cin, 1);
131 * get a string. make it an internal symbol.
134 gsym(RR *rp, Scan *sp)
144 if(sp->ep - sp->p < n)
145 return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
148 sp->err = "illegal string (symbol)";
151 strncpy(sym, (char*)sp->p, n);
153 if (strlen(sym) != n)
154 sp->err = "symbol shorter than declared length";
157 return dnlookup(sym, Csym, 1);
161 * get a string. don't make it an internal symbol.
164 gstr(RR *rp, Scan *sp)
175 if(sp->ep - sp->p < n)
176 return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
179 sp->err = "illegal string";
182 strncpy(sym, (char*)sp->p, n);
184 if (strlen(sym) != n)
185 sp->err = "string shorter than declared length";
188 t = emalloc(sizeof(*t));
195 * get a sequence of bytes
198 gbytes(RR *rp, Scan *sp, uchar **p, int n)
200 *p = nil; /* i think this is a good idea */
204 return errneg(rp, sp, n);
205 if(sp->ep - sp->p < n)
206 return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes");
208 memmove(*p, sp->p, n);
215 * get a domain name. 'to' must point to a buffer at least Domlen+1 long.
218 gname(char *to, RR *rp, Scan *sp)
220 int len, off, pointer, n;
221 char *tostart, *toend;
225 if(sp->err || sp->stop)
230 dnslog("gname: %R: nil sp->p", rp);
234 for(len = 0; *p && p < sp->ep; len += (pointer? 0: n+1)) {
237 case 0: /* normal label */
239 n = *p++ & 077; /* pick up length */
241 sp->err = "bad name length";
244 if(len + n < Domlen - 1){
246 errtoolong(rp, sp, toend - to, n,
256 errtoolong(rp, sp, toend - to, 2,
257 "more name components but no bytes left");
263 case 0100: /* edns extended label type, rfc 2671 */
265 * treat it like an EOF for now; it seems to be at
266 * the end of a long tcp reply.
268 dnslog("edns label; first byte 0%o = '%c'", *p, *p);
271 case 0200: /* reserved */
272 sp->err = "reserved-use label present";
274 case 0300: /* pointer to other spot in message */
276 sp->err = "pointer loop";
279 off = (p[0] & 077)<<8 | p[1];
282 sp->err = "bad pointer";
291 sp->p += len + 2; /* + 2 for pointer */
293 sp->p += len + 1; /* + 1 for the null domain */
301 * ms windows 2000 seems to get the bytes backward in the type field
302 * of ptr records, so return a format error as feedback.
305 mstypehack(Scan *sp, ushort type, char *where)
307 if ((uchar)type == 0 && (type>>8) != 0) {
309 // dnslog("%s: byte-swapped type field in ptr rr from win2k",
311 if (sp->rcode == Rok)
318 #define NAME(x) gname(x, rp, sp)
319 #define SYMBOL(x) ((x) = gsym(rp, sp))
320 #define STRING(x) ((x) = gstr(rp, sp))
321 #define USHORT(x) ((x) = gshort(rp, sp))
322 #define ULONG(x) ((x) = glong(rp, sp))
323 #define UCHAR(x) ((x) = gchar(rp, sp))
324 #define V4ADDR(x) ((x) = gv4addr(rp, sp))
325 #define V6ADDR(x) ((x) = gv6addr(rp, sp))
326 #define BYTES(x, y) ((y) = gbytes(rp, sp, &(x), len - (sp->p - data)))
329 * convert the next RR from a message
332 convM2RR(Scan *sp, char *what)
334 int type, class, len, left;
335 char dname[Domlen+1];
346 type = mstypehack(sp, type, "convM2RR");
348 rp->owner = dnlookup(dname, class, 1);
352 USHORT(len); /* length of data following */
355 left = sp->ep - sp->p;
358 * ms windows generates a lot of badly-formatted hints.
359 * hints are only advisory, so don't log complaints about them.
360 * it also generates answers in which p overshoots ep by exactly
361 * one byte; this seems to be harmless, so don't log them either.
364 !(strcmp(what, "hints") == 0 ||
365 sp->p == sp->ep + 1 && strcmp(what, "answers") == 0))
366 errtoolong(rp, sp, left, len, "convM2RR");
367 if(sp->err || sp->rcode || sp->stop){
371 /* even if we don't log an error message, truncate length to fit data */
377 /* unknown type, just ignore it */
390 rp->host = dnlookup(NAME(dname), Cin, 1);
394 rp->mb = dnlookup(NAME(dname), Cin, 1);
397 rp->rmb = dnlookup(NAME(dname), Cin, 1);
398 rp->mb = dnlookup(NAME(dname), Cin, 1);
402 rp->host = dnlookup(NAME(dname), Cin, 1);
411 rp->ptr = dnlookup(NAME(dname), Cin, 1);
414 rp->host = dnlookup(NAME(dname), Cin, 1);
415 rp->rmb = dnlookup(NAME(dname), Cin, 1);
416 ULONG(rp->soa->serial);
417 ULONG(rp->soa->refresh);
418 ULONG(rp->soa->retry);
419 ULONG(rp->soa->expire);
420 ULONG(rp->soa->minttl);
423 USHORT(rp->srv->pri);
424 USHORT(rp->srv->weight);
427 * rfc2782 sez no name compression but to be
428 * backward-compatible with rfc2052, we try to expand the name.
429 * if the length is under 64 bytes, either interpretation is
430 * fine; if it's longer, we'll assume it's compressed,
431 * as recommended by rfc3597.
433 rp->host = dnlookup(NAME(dname), Cin, 1);
438 while(sp->p - data < len){
445 BYTES(rp->null->data, rp->null->dlen);
448 rp->rmb = dnlookup(NAME(dname), Cin, 1);
449 rp->rp = dnlookup(NAME(dname), Cin, 1);
453 USHORT(rp->key->flags);
454 UCHAR(rp->key->proto);
456 BYTES(rp->key->data, rp->key->dlen);
459 USHORT(rp->sig->type);
461 UCHAR(rp->sig->labels);
464 ULONG(rp->sig->incep);
465 USHORT(rp->sig->tag);
466 rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
467 BYTES(rp->sig->data, rp->sig->dlen);
470 USHORT(rp->cert->type);
471 USHORT(rp->cert->tag);
472 UCHAR(rp->cert->alg);
473 BYTES(rp->cert->data, rp->cert->dlen);
476 UCHAR(rp->caa->flags);
477 SYMBOL(rp->caa->tag);
478 BYTES(rp->caa->data, rp->caa->dlen);
481 if(sp->p - data != len) {
485 * ms windows 2000 generates cname queries for reverse lookups
486 * with this particular error. don't bother logging it.
488 * server: input error: bad cname RR len (actual 2 != len 0):
489 * 235.9.104.135.in-addr.arpa cname
490 * 235.9.104.135.in-addr.arpa from 135.104.9.235
492 if (type == Tcname && sp->p - data == 2 && len == 0)
494 if (len > sp->p - data){
495 dnslog("bad %s RR len (%d bytes nominal, %zud actual): %R",
496 rrname(type, ptype, sizeof ptype), len,
502 // if(rp) dnslog("convM2RR: got %R", rp);
507 * convert the next question from a message
512 char dname[Domlen+1];
520 if(sp->err || sp->rcode || sp->stop)
523 type = mstypehack(sp, type, "convM2Q");
525 rp->owner = dnlookup(dname, class, 1);
531 rrloop(Scan *sp, char *what, int count, int quest)
536 if(sp->err || sp->rcode || sp->stop)
540 for(i = 0; i < count; i++){
541 rp = quest? convM2Q(sp): convM2RR(sp, what);
544 setmalloctag(rp, getcallerpc(&sp));
546 * it might be better to ignore the bad rr, possibly break out,
547 * but return the previous rrs, if any. that way our callers
548 * would know that they had got a response, however ill-formed.
550 if(sp->err || sp->rcode || sp->stop){
558 // setmalloctag(first, getcallerpc(&sp));
563 * convert the next DNS from a message stream.
564 * if there are formatting errors or the like during parsing of the message,
565 * set *codep to the outgoing response code (e.g., Rformat), which will
566 * abort processing and reply immediately with the outgoing response code.
569 convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep)
579 memset(sp, 0, sizeof *sp);
580 sp->base = sp->p = buf;
583 sp->errbuf[0] = '\0';
586 memset(m, 0, sizeof *m);
594 m->qd = rrloop(sp, "questions", m->qdcount, 1);
595 m->an = rrloop(sp, "answers", m->ancount, 0);
596 m->ns = rrloop(sp, "nameservers",m->nscount, 0);
600 err = strdup(sp->err); /* live with bad ar's */
601 m->ar = rrloop(sp, "hints", m->arcount, 0);