1 /* DNS packet handling routines for rbldnsd
2 */
3
4 #include <string.h>
5 #include <time.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <netdb.h>
12 #include <syslog.h>
13 #include "rbldnsd.h"
14
15 #ifndef NO_IPv6
16 # ifndef NI_MAXHOST
17 # define IPSIZE 1025
18 # else
19 # define IPSIZE NI_MAXHOST
20 # endif
21 #else
22 # define IPSIZE 16
23 #endif
24
25 #define MAX_GLUE (MAX_NS*2)
26
27 static int addrr_soa(struct dnspacket *pkt, const struct zone *zone, int auth);
28 static int addrr_ns(struct dnspacket *pkt, const struct zone *zone, int auth);
29 static int version_req(struct dnspacket *pkt, const struct dnsquery *qry);
30
31 /* DNS packet:
32 * bytes comment */
33 /* 0:1 identifier (client supplied) */
34 #define p_id1 0
35 #define p_id2 1
36 /* 2 flags1 */
37 #define p_f1 2
38 #define pf1_qr 0x80 /* query response flag */
39 #define pf1_opcode 0x78 /* opcode, 0 = query */
40 #define pf1_aa 0x04 /* auth answer */
41 #define pf1_tc 0x02 /* truncation flag */
42 #define pf1_rd 0x01 /* recursion desired (may be set in query) */
43 /* 3 flags2 */
44 #define p_f2 3
45 #define pf2_ra 0x80 /* recursion available */
46 #define pf2_z 0x70 /* reserved */
47 #define pf2_rcode 0x0f /* response code */
48 /* 0 ok, 1 format error, 2 servfail, 3 nxdomain, 4 notimpl, 5 refused */
49 /* 4:5 qdcount (numqueries) */
50 #define p_qdcnt1 4
51 #define p_qdcnt2 5
52 /* 6:7 ancount (numanswers) */
53 #define p_ancnt1 6
54 #define p_ancnt2 7
55 /* 8:9 nscount (numauthority) */
56 #define p_nscnt1 8
57 #define p_nscnt2 9
58 /* 10:11 arcount (numadditional) */
59 #define p_arcnt1 10
60 #define p_arcnt2 11
61 #define p_hdrsize 12 /* size of packet header */
62 /* next is a DN name, a series of labels with first byte is label's length,
63 * terminated by zero-length label (i.e. at least one zero byte is here)
64 * next two bytes are query type (A, SOA etc)
65 * next two bytes are query class (IN, HESIOD etc)
66 */
67
68 static int
parsequery(struct dnspacket * pkt,unsigned qlen,struct dnsquery * qry)69 parsequery(struct dnspacket *pkt, unsigned qlen,
70 struct dnsquery *qry) {
71
72 /* parsing incoming query. Untrusted data read directly from the network.
73 * pkt->p_buf is a buffer - data that was read (DNS_EDNS0_MAXPACKET max).
74 * qlen is number of bytes actually read (packet length)
75 * first p_hdrsize bytes is header, next is query DN,
76 * next are QTYPE and QCLASS (2x2 bytes).
77 * If NSCNT==0 && ARCNT==1, and an OPT record comes after the query,
78 * EDNS0 packet size gets extracted from the OPT record.
79 * Rest of data is ignored.
80 * Returns true on success, 0 on failure.
81 * Upon successeful return, pkt->p_sans = pkt->p_cur points to the end of
82 * the query section (where our answers will be placed), and
83 * pkt->p_endp is initialized to point to the real end of answers.
84 * Real end of answers is:
85 * for non-EDNS0-aware clients it's pkt->p_buf+DNS_MAXPACKET, and
86 * if a vaild EDNS0 UDPsize is given, it will be pkt->p_buf+UDPsize-11,
87 * with the 11 bytes needed for a minimal OPT record.
88 * In replypacket() we check whenever all our answers fits in standard
89 * UDP buffer size (DNS_MAXPACKET), and if not (which means we're replying
90 * to EDNS0-aware client due to the above rules), we just add proper OPT
91 * record at the end.
92 */
93
94 register unsigned const char *q = pkt->p_buf;
95 register unsigned const char *x, *e;
96 register unsigned char *d;
97 unsigned qlab; /* number of labels in qDN */
98
99 x = q + qlen - 5; /* last possible qDN zero terminator position */
100 /* qlen isn't needed anymore, it'll be used as length of qDN below */
101
102 if (q + p_hdrsize > x) /* short packet (header isn't here) */
103 return 0;
104 else if (q + p_hdrsize + DNS_MAXDN <= x)
105 x = q + p_hdrsize + DNS_MAXDN - 1; /* constrain query DN to DNS_MAXDN */
106
107 if (q[p_f1] & pf1_qr) /* response packet?! */
108 return 0;
109 if (q[p_qdcnt1] || q[p_qdcnt2] != 1) /* qdcount should be == 1 */
110 return 0;
111
112 /* parse and lowercase query DN, count and init labels */
113 qlab = 0; /* number of labels so far */
114 q += p_hdrsize; /* start of qDN */
115 d = qry->q_dn; /* destination lowercased DN */
116 while((*d = *q) != 0) { /* loop by DN lables */
117 qry->q_lptr[qlab++] = d++; /* another label */
118 e = q + *q + 1; /* end of this label */
119 if (*q > DNS_MAXLABEL /* too long label? */
120 || e > x) /* or it ends past packet? */
121 return 0;
122 /* lowercase it */
123 ++q; /* length */
124 do *d++ = dns_dnlc(*q); /* lowercase each char */
125 while(++q < e); /* until end of label */
126 }
127 /* d points to qDN terminator now */
128 qry->q_dnlen = d - qry->q_dn + 1;
129 qry->q_dnlab = qlab;
130
131 /* q is end of qDN. decode qtype and qclass, and prepare for an answer */
132 ++q;
133 qry->q_type = ((unsigned)(q[0]) << 8) | q[1];
134 qry->q_class = ((unsigned)(q[2]) << 8) | q[3];
135
136 q += 4;
137 pkt->p_sans = (unsigned char *)q; /* answers will start here */
138 pkt->p_cur = (unsigned char *)q; /* and current answer pointer is here */
139 d = pkt->p_buf;
140 if (q < x &&
141 d[p_nscnt1] == 0 && d[p_nscnt2] == 0 &&
142 d[p_arcnt1] == 0 && d[p_arcnt2] == 1 &&
143 q[0] == 0 /* empty DN */ &&
144 q[1] == (DNS_T_OPT>>8) && q[2] == (DNS_T_OPT&255)) {
145 qlen = (((unsigned)q[3]) << 8) | q[4];
146 /* 11 bytes are needed to encode minimal EDNS0 OPT record */
147 if (qlen < DNS_MAXPACKET + 11)
148 qlen = DNS_MAXPACKET;
149 else if (qlen > sizeof(pkt->p_buf) - 11)
150 qlen = sizeof(pkt->p_buf) - 11;
151 else
152 qlen -= 11;
153 pkt->p_endp = d + qlen;
154 }
155 else
156 pkt->p_endp = d + DNS_MAXPACKET;
157
158 return 1;
159 }
160
161 #define digit(c) ((c) >= '0' && (c) <= '9')
162 #define d2n(c) ((unsigned)((c) - '0'))
163
dntoip4addr(const unsigned char * q,ip4addr_t * ap)164 static int dntoip4addr(const unsigned char *q, ip4addr_t *ap) {
165 unsigned o, a = 0;
166 #define oct(q,o) \
167 switch(*q) { \
168 case 1: \
169 if (!digit(q[1])) \
170 return 0; \
171 o = d2n(q[1]); \
172 break; \
173 case 2: \
174 if (!digit(q[1]) || !digit(q[2])) \
175 return 0; \
176 o = d2n(q[1]) * 10 + d2n(q[2]); \
177 break; \
178 case 3: \
179 if (!digit(q[1]) || !digit(q[2]) || !digit(q[3])) \
180 return 0; \
181 o = d2n(q[1]) * 100 + d2n(q[2]) * 10 + d2n(q[3]); \
182 if (o > 255) return 0; \
183 break; \
184 default: return 0; \
185 }
186 oct(q,o); a |= o; q += *q + 1;
187 oct(q,o); a |= o << 8; q += *q + 1;
188 oct(q,o); a |= o << 16; q += *q + 1;
189 oct(q,o); a |= o << 24;
190 *ap = a;
191 return 1;
192 #undef oct
193 }
194
dntoip6addr(const unsigned char * q,ip6oct_t ap[IP6ADDR_FULL])195 static int dntoip6addr(const unsigned char *q, ip6oct_t ap[IP6ADDR_FULL]) {
196 unsigned o1, o2, c;
197 for(c = IP6ADDR_FULL; c; ) {
198 if (*q++ != 1)
199 return 0;
200 if (digit(*q)) o2 = d2n(*q++);
201 else if (*q >= 'a' && *q <= 'f') o2 = *q++ - 'a' + 10;
202 else return 0;
203 if (*q++ != 1)
204 return 0;
205 if (digit(*q)) o1 = d2n(*q++);
206 else if (*q >= 'a' && *q <= 'f') o1 = *q++ - 'a' + 10;
207 else return 0;
208 ap[--c] = (o1 << 4) | o2;
209 }
210 return 1;
211 }
212
213 static const ip6oct_t ip6mapped_pfx[12] =
214 "\0\0\0\0\0\0\0\0"
215 "\0\0\377\377";
216
217 /* parse DN (as in 4.3.2.1.in-addr.arpa) to ip4addr_t (4 octets 0..255).
218 * parse DN (as in 0.1.2.3.4.5...f.base.dn) to ip6 address (32 nibbles 0..f)
219 */
dntoip(struct dnsqinfo * qi,int flags)220 static void dntoip(struct dnsqinfo *qi, int flags) {
221
222 const unsigned char *q = qi->qi_dn;
223 unsigned qlab = qi->qi_dnlab;
224
225 qi->qi_ip4valid = qlab == 4 && dntoip4addr(q, &qi->qi_ip4);
226 if (qi->qi_ip4valid)
227 qi->qi_ip6valid = 0;
228 else {
229 qi->qi_ip6valid =
230 qlab == 32 && qi->qi_dnlen0 == 64 && dntoip6addr(q, qi->qi_ip6);
231 if (qi->qi_ip6valid && (flags & DSTF_IP4REV)) {
232 if (qi->qi_ip6[0] == 0x20 && qi->qi_ip6[1] == 0x02) {
233 /* construct IP4 from 2002:V4ADDR::/48 6to4 address, RFC3056 */
234 qi->qi_ip4 = unpack32(qi->qi_ip6 + 2);
235 qi->qi_ip4valid = 1;
236 }
237 else if (memcmp(qi->qi_ip6, ip6mapped_pfx, sizeof(ip6mapped_pfx)) == 0) {
238 /* construct IP4 from IP4MAPPED, ::ffff:V4ADDR */
239 qi->qi_ip4 = unpack32(qi->qi_ip6 + 12);
240 qi->qi_ip4valid = 1;
241 qi->qi_ip6valid = 0; /* don't bother looking v6 */
242 }
243 }
244 }
245 }
246
247 const struct zone *
findqzone(const struct zone * zone,unsigned dnlen,unsigned dnlab,unsigned char * const * const dnlptr,struct dnsqinfo * qi)248 findqzone(const struct zone *zone,
249 unsigned dnlen, unsigned dnlab, unsigned char *const *const dnlptr,
250 struct dnsqinfo *qi) {
251 const unsigned char *q;
252
253 for(;; zone = zone->z_next) {
254 if (!zone) return NULL;
255 if (zone->z_dnlab > dnlab) continue;
256 q = dnlptr[dnlab - zone->z_dnlab];
257 if (memcmp(zone->z_dn, q, zone->z_dnlen - 1)) continue;
258 break;
259 }
260 qi->qi_dn = dnlptr[0];
261 qi->qi_dnlptr = dnlptr;
262 qi->qi_dnlab = dnlab - zone->z_dnlab;
263 qi->qi_dnlen0 = dnlen - zone->z_dnlen;
264
265 if (zone->z_dstflags & (DSTF_IP4REV|DSTF_IP6REV)) /* IP address */
266 dntoip(qi, zone->z_dstflags);
267
268 return zone;
269 }
270
271 #ifdef NO_STATS
272 # define do_stats(x)
273 #else
274 # define do_stats(x) x
275 #endif
276
277 /* construct reply to a query. */
replypacket(struct dnspacket * pkt,unsigned qlen,struct zone * zone)278 int replypacket(struct dnspacket *pkt, unsigned qlen, struct zone *zone) {
279
280 struct dnsquery qry; /* query structure */
281 struct dnsqinfo qi; /* query info structure */
282 unsigned char *h = pkt->p_buf; /* packet's header */
283 const struct dslist *dsl;
284 int found;
285 extern int lazy; /*XXX hack*/
286
287 pkt->p_substrr = 0;
288 /* check global ACL */
289 if (g_dsacl && g_dsacl->ds_stamp) {
290 found = ds_acl_query(g_dsacl, pkt);
291 if (found & NSQUERY_IGNORE) {
292 do_stats(gstats.q_err += 1; gstats.b_in += qlen);
293 return 0;
294 }
295 }
296 else
297 found = 0;
298
299 if (!parsequery(pkt, qlen, &qry)) {
300 do_stats(gstats.q_err += 1; gstats.b_in += qlen);
301 return 0;
302 }
303
304 /* from now on, we see (almost?) valid dns query, should reply */
305
306 #define setnonauth(h) (h[p_f1] &= ~pf1_aa)
307 #define _refuse(code,lab) \
308 do { setnonauth(h); h[p_f2] = (code); goto lab; } while(0)
309 #define refuse(code) _refuse(code, err_nz)
310 #define rlen() pkt->p_cur - h
311
312 /* construct reply packet */
313
314 /* identifier already in place */
315 /* flags will be set up later */
316 /* qdcount already set up in query */
317 /* all counts (qd,an,ns,ar) are <= 255 due to size limit */
318 h[p_ancnt1] = h[p_ancnt2] = 0;
319 h[p_nscnt1] = h[p_nscnt2] = 0;
320 h[p_arcnt1] = h[p_arcnt2] = 0;
321
322 if (h[p_f1] & (pf1_opcode | pf1_aa | pf1_tc | pf1_qr)) {
323 h[p_f1] = pf1_qr;
324 refuse(DNS_R_NOTIMPL);
325 }
326 h[p_f1] |= pf1_qr;
327 if (qry.q_class == DNS_C_IN)
328 h[p_f1] |= pf1_aa;
329 else if (qry.q_class != DNS_C_ANY) {
330 if (version_req(pkt, &qry)) {
331 do_stats(gstats.q_ok += 1; gstats.b_in += qlen; gstats.b_out += rlen());
332 return rlen();
333 }
334 else
335 refuse(DNS_R_REFUSED);
336 }
337 switch(qry.q_type) {
338 case DNS_T_ANY: qi.qi_tflag = NSQUERY_ANY; break;
339 case DNS_T_A: qi.qi_tflag = NSQUERY_A; break;
340 case DNS_T_TXT: qi.qi_tflag = NSQUERY_TXT; break;
341 case DNS_T_NS: qi.qi_tflag = NSQUERY_NS; break;
342 case DNS_T_SOA: qi.qi_tflag = NSQUERY_SOA; break;
343 case DNS_T_MX: qi.qi_tflag = NSQUERY_MX; break;
344 default:
345 if (qry.q_type >= DNS_T_TSIG)
346 refuse(DNS_R_NOTIMPL);
347 qi.qi_tflag = NSQUERY_OTHER;
348 }
349 qi.qi_tflag |= found;
350 h[p_f2] = DNS_R_NOERROR;
351
352 /* find matching zone */
353 zone = (struct zone*)
354 findqzone(zone, qry.q_dnlen, qry.q_dnlab, qry.q_lptr, &qi);
355 if (!zone) /* not authoritative */
356 refuse(DNS_R_REFUSED);
357
358 /* found matching zone */
359 #undef refuse
360 #define refuse(code) _refuse(code, err_z)
361 do_stats(zone->z_stats.b_in += qlen);
362
363 if (zone->z_dsacl && zone->z_dsacl->ds_stamp) {
364 qi.qi_tflag |= ds_acl_query(zone->z_dsacl, pkt);
365 if (qi.qi_tflag & NSQUERY_IGNORE) {
366 do_stats(gstats.q_err += 1);
367 return 0;
368 }
369 }
370
371 if (!zone->z_stamp) /* do not answer if not loaded */
372 refuse(DNS_R_SERVFAIL);
373
374 if (qi.qi_tflag & NSQUERY_REFUSE)
375 refuse(DNS_R_REFUSED);
376
377 if ((found = call_hook(query_access, (pkt->p_peer, zone, &qi)))) {
378 if (found < 0) return 0;
379 refuse(DNS_R_REFUSED);
380 }
381
382 if (qi.qi_dnlab == 0) { /* query to base zone: SOA and NS */
383
384 found = NSQUERY_FOUND;
385
386 /* NS and SOA with auth=0 will only touch answer section */
387 if ((qi.qi_tflag & NSQUERY_SOA) && !addrr_soa(pkt, zone, 0))
388 found = 0;
389 else
390 if ((qi.qi_tflag & NSQUERY_NS) && !addrr_ns(pkt, zone, 0))
391 found = 0;
392 if (!found) {
393 pkt->p_cur = pkt->p_sans;
394 h[p_ancnt2] = h[p_nscnt2] = 0;
395 refuse(DNS_R_REFUSED);
396 }
397
398 }
399 else /* not to zone base DN */
400 found = 0;
401
402 /* search the datasets */
403 for(dsl = zone->z_dsl; dsl; dsl = dsl->dsl_next)
404 found |= dsl->dsl_queryfn(dsl->dsl_ds, &qi, pkt);
405
406 if (found & NSQUERY_ADDPEER) {
407 #ifdef NO_IPv6
408 addrr_a_txt(pkt, qi.qi_tflag, pkt->p_substrr,
409 inet_ntoa(((struct sockaddr_in*)pkt->p_peer)->sin_addr),
410 pkt->p_substds);
411 #else
412 char subst[IPSIZE];
413 if (getnameinfo(pkt->p_peer, pkt->p_peerlen,
414 subst, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
415 subst[0] = '\0';
416 addrr_a_txt(pkt, qi.qi_tflag, pkt->p_substrr, subst, pkt->p_substds);
417 #endif
418 }
419
420 /* now complete the reply: add AUTH etc sections */
421 /* addrr_ns(auth=1) should be called last as it fills in
422 * both AUTH and ADDITIONAL sections */
423 if (!found) { /* negative result */
424 addrr_soa(pkt, zone, 1); /* add SOA if any to AUTHORITY */
425 h[p_f2] = DNS_R_NXDOMAIN;
426 do_stats(zone->z_stats.q_nxd += 1);
427 }
428 else {
429 if (!h[p_ancnt2]) { /* positive reply, no answers */
430 addrr_soa(pkt, zone, 1); /* add SOA if any to AUTHORITY */
431 }
432 else if (zone->z_nns &&
433 /* (!(qi.qi_tflag & NSQUERY_NS) || qi.qi_dnlab) && */
434 !lazy)
435 addrr_ns(pkt, zone, 1); /* add nameserver records to positive reply */
436 do_stats(zone->z_stats.q_ok += 1);
437 }
438 (void)call_hook(query_result, (pkt->p_peer, zone, &qi, found));
439 if (rlen() > DNS_MAXPACKET) { /* add OPT record for long replies */
440 /* as per parsequery(), we always have 11 bytes for minimal OPT record at
441 * the end of our reply packet, OR rlen() does not exceed DNS_MAXPACKET */
442 h[p_arcnt2] += 1; /* arcnt is limited to 254 records */
443 h = pkt->p_cur;
444 *h++ = 0; /* empty (root) DN */
445 PACK16S(h, DNS_T_OPT);
446 PACK16S(h, DNS_EDNS0_MAXPACKET);
447 *h++ = 0; *h++ = 0; /* RCODE and version */
448 *h++ = 0; *h++ = 0; /* rest of the TTL field */
449 *h++ = 0; *h++ = 0; /* RDLEN */
450 pkt->p_cur = h;
451 h = pkt->p_buf; /* restore for rlen() to work */
452 }
453 do_stats(zone->z_stats.b_out += rlen());
454 return rlen();
455
456 err_nz:
457 do_stats(gstats.q_err += 1; gstats.b_in += qlen; gstats.b_out += rlen());
458 return rlen();
459
460 err_z:
461 do_stats(zone->z_stats.q_err += 1; zone->z_stats.b_out += rlen());
462 return rlen();
463 }
464
465 #define fit(pkt, c, bytes) ((c) + (bytes) <= (pkt)->p_endp)
466
467
468 /* DN compression pointers/structures */
469
470 /* We store pre-computed RRs for NS and SOA records in special
471 * cache buffers referenced to by zone structure.
472 *
473 * The precomputed RRs consists of ready-to-be-sent data (with
474 * all record types/classes, TTLs, and data in place), modulo
475 * compressed DN backreferences. When this cached data will be
476 * copied into answer packet, we'll need to adjust "jumps" in
477 * DN name compressions to reflect actual position of the data
478 * in answer packet.
479 *
480 * Cache data is calculated as if it where inside some packet,
481 * where it's start is exactly at the beginning of cached/precomputed
482 * record, and with zone's base DN (with class and type) being in
483 * question section immediately BEFORE the data (i.e. before our
484 * "virtual packet"). So some DN compression offsets (pointers)
485 * will be negative (referring to the query section of actual answer,
486 * as zone base DN will be present in answer anyway), and some will
487 * be positive (referring to this very record in actual answer).
488 */
489
490 struct dnjump { /* one DN "jump": */
491 unsigned char *pos; /* position in precomputed packet where the jump is */
492 int off; /* jump offset relative to beginning of the RRs */
493 };
494
495 struct dnptr { /* domain pointer for DN compression */
496 const unsigned char *dn; /* actual (complete) domain name */
497 int off; /* jump offset relative to start of RRs */
498 };
499
500 struct dncompr { /* DN compression structure */
501 struct dnptr ptr[256]; /* array of all known domain names */
502 struct dnptr *lptr; /* last unused slot in ptr[] */
503 unsigned char *buf; /* buffer for the cached RRs */
504 unsigned char *bend; /* pointer to past the end of buf */
505 struct dnjump *jump; /* current jump ptr (array of jumps) */
506 };
507
508 #define CACHEBUF_SIZE (DNS_MAXPACKET-p_hdrsize-4)
509 /* maxpacket minus header minus (class+type) */
510
511 /* initialize compression/cache structures */
512 static unsigned char *
dnc_init(struct dncompr * compr,unsigned char * buf,unsigned bufsize,struct dnjump * jump,const unsigned char * dn)513 dnc_init(struct dncompr *compr,
514 unsigned char *buf, unsigned bufsize, struct dnjump *jump,
515 const unsigned char *dn) {
516 struct dnptr *ptr;
517 unsigned char *cpos;
518
519 compr->buf = buf; compr->bend = buf + bufsize;
520 compr->jump = jump;
521
522 cpos = buf - dns_dnlen(dn) - 4; /* current position: qDN BEFORE the RRs */
523 ptr = compr->ptr;
524
525 while(*dn) {
526 ptr->dn = dn;
527 ptr->off = cpos - buf;
528 ++ptr;
529 cpos += *dn + 1;
530 dn += *dn + 1;
531 }
532 compr->lptr = ptr;
533 return cpos + 5;
534 }
535
536 /* add one DN into cache, adjust compression pointers and current pointer */
537 static unsigned char *
dnc_add(struct dncompr * compr,unsigned char * cpos,const unsigned char * dn)538 dnc_add(struct dncompr *compr, unsigned char *cpos, const unsigned char *dn) {
539 struct dnptr *ptr;
540
541 while(*dn) {
542 /* lookup DN in already stored names */
543 for(ptr = compr->ptr; ptr < compr->lptr; ++ptr) {
544 if (!dns_dnequ(ptr->dn, dn))
545 continue;
546 /* found one, make a jump to it */
547 if (cpos + 2 >= compr->bend) return NULL;
548 compr->jump->pos = cpos;
549 compr->jump->off = ptr->off;
550 ++compr->jump;
551 return cpos + 2;
552 }
553 /* not found, add it to the list of known DNs... */
554 if (cpos + *dn + 1 >= compr->bend)
555 return NULL; /* does not fit */
556 if (ptr < compr->ptr + sizeof(compr->ptr) / sizeof(compr->ptr[0])) {
557 ptr->dn = dn;
558 ptr->off = cpos - compr->buf;
559 ++compr->lptr;
560 }
561 /* ...and add one label into the "packet" */
562 memcpy(cpos, dn, *dn + 1);
563 cpos += *dn + 1;
564 dn += *dn + 1;
565 }
566 if (cpos + 1 >= compr->bend)
567 return NULL;
568 *cpos++ = '\0';
569 return cpos;
570 }
571
572 /* finalize RRs: remember it's size and number of jumps */
dnc_finish(struct dncompr * compr,unsigned char * cptr,unsigned * sizep,struct dnjump ** jendp)573 static void dnc_finish(struct dncompr *compr, unsigned char *cptr,
574 unsigned *sizep, struct dnjump **jendp) {
575 *sizep = cptr - compr->buf;
576 *jendp = compr->jump;
577 }
578
579 /* place pre-cached RRs into the packet, adjusting jumps */
580 static int
dnc_final(struct dnspacket * pkt,const unsigned char * data,unsigned dsize,const struct dnjump * jump,const struct dnjump * jend)581 dnc_final(struct dnspacket *pkt,
582 const unsigned char *data, unsigned dsize,
583 const struct dnjump *jump,
584 const struct dnjump *jend) {
585 const unsigned qoff = (pkt->p_sans - pkt->p_buf) + 0xc000;
586 const unsigned coff = (pkt->p_cur - pkt->p_buf) + 0xc000;
587 unsigned pos;
588 if (!fit(pkt, pkt->p_cur, dsize))
589 return 0;
590 /* first, adjust offsets - in cached data anyway */
591 while(jump < jend) {
592 /* jump to either query section or this very RRs */
593 pos = jump->off + (jump->off < 0 ? qoff : coff);
594 PACK16(jump->pos, pos);
595 ++jump;
596 }
597 /* and finally, copy the RRs into answer packet */
598 memcpy(pkt->p_cur, data, dsize);
599 pkt->p_cur += dsize;
600 return 1;
601 }
602
603
604 struct zonesoa { /* cached SOA RR */
605 unsigned size; /* size of the RR */
606 unsigned ttloff; /* offset of the TTL field */
607 const unsigned char *minttl; /* pointer to minttl in data */
608 struct dnjump jump[3]; /* jumps to fix: 3 max (qdn, odn, pdn) */
609 struct dnjump *jend; /* last jump */
610 unsigned char data[CACHEBUF_SIZE];
611 };
612
613 struct zonens { /* cached NS RRs */
614 unsigned nssize; /* size of all NS RRs */
615 unsigned tsize; /* size of NS+glue recs */
616 struct dnjump jump[MAX_NS*2+MAX_GLUE];/* jumps: for qDNs and for NSes */
617 struct dnjump *nsjend; /* last NS jump */
618 struct dnjump *tjend; /* last glue jump */
619 unsigned char data[CACHEBUF_SIZE];
620 };
621
init_zones_caches(struct zone * zonelist)622 void init_zones_caches(struct zone *zonelist) {
623 while(zonelist) {
624 if (!zonelist->z_dsl) {
625 char name[DNS_MAXDOMAIN];
626 dns_dntop(zonelist->z_dn, name, sizeof(name));
627 error(0, "missing data for zone `%s'", name);
628 }
629 zonelist->z_zsoa = tmalloc(struct zonesoa);
630 /* for NS RRs, we allocate MAX_NS caches:
631 * each stores one variant of NS rotation */
632 zonelist->z_zns = (struct zonens *)emalloc(sizeof(struct zonens) * MAX_NS);
633 zonelist = zonelist->z_next;
634 }
635 }
636
637 /* update SOA RR cache */
638
update_zone_soa(struct zone * zone,const struct dssoa * dssoa)639 int update_zone_soa(struct zone *zone, const struct dssoa *dssoa) {
640 struct zonesoa *zsoa;
641 unsigned char *cpos;
642 struct dncompr compr;
643 unsigned t;
644 unsigned char *sizep;
645
646 zsoa = zone->z_zsoa;
647 zsoa->size = 0;
648 if (!(zone->z_dssoa = dssoa)) return 1;
649
650 cpos = dnc_init(&compr, zsoa->data, sizeof(zsoa->data),
651 zsoa->jump, zone->z_dn);
652
653 cpos = dnc_add(&compr, cpos, zone->z_dn);
654 PACK16S(cpos, DNS_T_SOA);
655 PACK16S(cpos, DNS_C_IN);
656 zsoa->ttloff = cpos - compr.buf;
657 PACK32S(cpos, dssoa->dssoa_ttl);
658 sizep = cpos;
659 cpos += 2;
660 cpos = dnc_add(&compr, cpos, dssoa->dssoa_odn);
661 if (!cpos) return 0;
662 cpos = dnc_add(&compr, cpos, dssoa->dssoa_pdn);
663 if (!cpos) return 0;
664 t = dssoa->dssoa_serial ? dssoa->dssoa_serial : zone->z_stamp;
665 PACK32S(cpos, t);
666 memcpy(cpos, dssoa->dssoa_n, 16); cpos += 16;
667 zsoa->minttl = cpos - 4;
668 t = cpos - sizep - 2;
669 PACK16(sizep, t);
670 dnc_finish(&compr, cpos, &zsoa->size, &zsoa->jend);
671
672 return 1;
673 }
674
addrr_soa(struct dnspacket * pkt,const struct zone * zone,int auth)675 static int addrr_soa(struct dnspacket *pkt, const struct zone *zone, int auth) {
676 const struct zonesoa *zsoa = zone->z_zsoa;
677 unsigned char *c = pkt->p_cur;
678 if (!zone->z_dssoa || !zsoa->size) {
679 if (!auth)
680 setnonauth(pkt->p_buf);
681 return 0;
682 }
683 if (!dnc_final(pkt, zsoa->data, zsoa->size, zsoa->jump, zsoa->jend)) {
684 if (!auth)
685 setnonauth(pkt->p_buf); /* non-auth answer as we can't fit the record */
686 return 0;
687 }
688 /* for AUTHORITY section for NXDOMAIN etc replies, use minttl as TTL */
689 if (auth) memcpy(c + zsoa->ttloff, zsoa->minttl, 4);
690 pkt->p_buf[auth ? p_nscnt2 : p_ancnt2]++;
691 return 1;
692 }
693
694 static unsigned char *
find_glue(struct zone * zone,const unsigned char * nsdn,struct dnspacket * pkt,const struct zone * zonelist)695 find_glue(struct zone *zone, const unsigned char *nsdn,
696 struct dnspacket *pkt, const struct zone *zonelist) {
697 struct dnsqinfo qi;
698 unsigned lab;
699 unsigned char dnbuf[DNS_MAXDN], *dp;
700 unsigned char *dnlptr[DNS_MAXLABELS];
701 const struct dslist *dsl;
702 const struct zone *qzone;
703
704 /* lowercase the nsdn and find label pointers */
705 lab = 0; dp = dnbuf;
706 while((*dp = *nsdn)) {
707 const unsigned char *e = nsdn + *nsdn + 1;
708 dnlptr[lab++] = dp++;
709 while(++nsdn < e)
710 *dp++ = dns_dnlc(*nsdn);
711 }
712
713 qzone = findqzone(zonelist, dp - dnbuf + 1, lab, dnlptr, &qi);
714 if (!qzone)
715 return NULL;
716
717 /* pefrorm fake query */
718 qi.qi_tflag = NSQUERY_A/*|NSQUERY_AAAA*/;
719 dp = pkt->p_cur;
720 for(dsl = qzone->z_dsl; dsl; dsl = dsl->dsl_next)
721 dsl->dsl_queryfn(dsl->dsl_ds, &qi, pkt);
722
723 if (dp == pkt->p_cur) {
724 char name[DNS_MAXDOMAIN];
725 dns_dntop(qi.qi_dn, name, sizeof(name));
726 zlog(LOG_WARNING, zone, "no glue record(s) for %.60s NS found", name);
727 return NULL;
728 }
729
730 return dp;
731 }
732
update_zone_ns(struct zone * zone,const struct dsns * dsns,unsigned ttl,const struct zone * zonelist)733 int update_zone_ns(struct zone *zone, const struct dsns *dsns, unsigned ttl,
734 const struct zone *zonelist) {
735 struct zonens *zns;
736 unsigned char *cpos, *sizep;
737 struct dncompr compr;
738 unsigned size, i, ns, nns;
739 const unsigned char *nsdna[MAX_NS];
740 const unsigned char *dn;
741 unsigned char *nsrrs[MAX_NS], *nsrre[MAX_NS];
742 unsigned nglue;
743 struct dnspacket pkt;
744
745 memset(&pkt, 0, sizeof(pkt));
746 pkt.p_sans = pkt.p_cur = pkt.p_buf + p_hdrsize;
747 pkt.p_endp = pkt.p_buf + CACHEBUF_SIZE + p_hdrsize;
748
749 for(nns = 0; dsns; dsns = dsns->dsns_next) {
750 i = 0;
751 while(i < nns && !dns_dnequ(nsdna[i], dsns->dsns_dn))
752 ++i;
753 if (i < nns)
754 continue;
755 if (nns >= MAX_NS) {
756 zlog(LOG_WARNING, zone,
757 "too many NS records specified, only first %d will be used", MAX_NS);
758 break;
759 }
760 nsdna[nns] = dsns->dsns_dn;
761 if ((nsrrs[nns] = find_glue(zone, dsns->dsns_dn, &pkt, zonelist)))
762 nsrre[nns] = pkt.p_cur;
763 ++nns;
764 }
765 /* number of additional records must not exceed 254: (room for EDNS0 OPT) */
766 nglue = pkt.p_buf[p_ancnt2];
767 if (pkt.p_buf[p_ancnt1] || nglue > 254) /* too many glue recs */
768 return 0;
769 /* check if we have enouth dnjump slots */
770 if (nns * 2 + nglue > sizeof(zns->jump)/sizeof(zns->jump[0]))
771 return 0;
772
773 memcpy(zone->z_nsdna, nsdna, nns * sizeof(nsdna[0]));
774 memset(nsdna + nns, 0, (MAX_NS - nns) * sizeof(nsdna[0]));
775 zone->z_nns = 0; /* for now, in case of error return */
776 zone->z_nsttl = ttl;
777
778 /* fill up nns variants of NS RRs ordering:
779 * zns is actually an array, not single structure */
780 ns = 0;
781 zns = zone->z_zns;
782 for(;;) {
783 cpos = dnc_init(&compr, zns->data, sizeof(zns->data),
784 zns->jump, zone->z_dn);
785
786 for(i = 0; i < nns; ++i) {
787 cpos = dnc_add(&compr, cpos, zone->z_dn);
788 if (!cpos || cpos + 10 > compr.bend) return 0;
789 PACK16S(cpos, DNS_T_NS);
790 PACK16S(cpos, DNS_C_IN);
791 PACK32S(cpos, ttl);
792 sizep = cpos; cpos += 2;
793 cpos = dnc_add(&compr, cpos, nsdna[i]);
794 if (!cpos) return 0;
795 size = cpos - sizep - 2;
796 PACK16(sizep, size);
797 }
798 dnc_finish(&compr, cpos, &zns->nssize, &zns->nsjend);
799
800 if (nglue)
801 for(i = 0; i < nns; ++i)
802 for(dn = nsrrs[i]; dn && dn < nsrre[i]; ) {
803 /* pack the glue record. dnjump, type+class, ttl, size (= 4 or 16) */
804 dn += 2;
805 size = 10 + dn[2+2+4+1];
806 cpos = dnc_add(&compr, cpos, zone->z_nsdna[i]);
807 if (!cpos || cpos + size > compr.bend) return 0;
808 memcpy(cpos, dn, size);
809 dn += size; cpos += size;
810 }
811 dnc_finish(&compr, cpos, &zns->tsize, &zns->tjend);
812
813 if (++ns >= nns) break;
814
815 /* rotate list of NSes */
816 dn = nsdna[0];
817 memmove(nsdna, nsdna + 1, (nns - 1) * sizeof(nsdna[0]));
818 nsdna[nns - 1] = dn;
819 ++zns;
820
821 }
822 zone->z_nns = nns;
823 zone->z_nglue = nglue;
824
825 return 1;
826 }
827
addrr_ns(struct dnspacket * pkt,const struct zone * zone,int auth)828 static int addrr_ns(struct dnspacket *pkt, const struct zone *zone, int auth) {
829 unsigned cns = zone->z_cns;
830 const struct zonens *zns = zone->z_zns + cns;
831 if (!zone->z_nns)
832 return 0;
833 /* if auth=1, we're adding last records (except maybe EDNS0 OPT),
834 * so it's ok to fill in both AUTH and ADDITIONAL sections. */
835 /* If we can't fit both NS and glue recs, try NS only, omitting glue.
836 * For auth=0, don't add glue records at all. */
837 if (auth && dnc_final(pkt, zns->data, zns->tsize, zns->jump, zns->tjend)) {
838 pkt->p_buf[p_nscnt2] += zone->z_nns;
839 pkt->p_buf[p_arcnt2] += zone->z_nglue;
840 }
841 else if (!dnc_final(pkt, zns->data, zns->nssize, zns->jump, zns->nsjend))
842 return 0;
843 else
844 /* we can't overflow p_ancnt2 (255 max) because addrr_ns(auth=0)
845 * is called before all other answers will be collected,
846 * and MAX_NS (zone->z_nns) is definitely less than 255 */
847 pkt->p_buf[auth ? p_nscnt2 : p_ancnt2] += zone->z_nns;
848 /* pick up next variation of NS ordering */
849 ++cns;
850 if (cns >= zone->z_nns)
851 cns = 0;
852 ((struct zone *)zone)->z_cns = cns;
853 return 1;
854 }
855
856 static unsigned
checkrr_present(register unsigned char * c,register unsigned char * e,unsigned dtp,const void * data,unsigned dsz,unsigned ttl)857 checkrr_present(register unsigned char *c, register unsigned char *e,
858 unsigned dtp, const void *data, unsigned dsz, unsigned ttl) {
859 /* check whenever we already have this (type of) RR in reply,
860 * ensure that all RRs of the same type has the same TTL */
861
862 const unsigned char dtp1 = dtp >> 8, dtp2 = dtp & 255;
863 unsigned t;
864
865 #define nextRR(c) ((c) + 12 + (c)[11])
866 #define hasRR(c,e) ((c) < (e))
867 #define sameRRT(c,dtp1,dtp2) ((c)[2] == (dtp1) && (c)[3] == (dtp2))
868 #define sameDATA(c,dsz,data) \
869 ((c)[11] == (dsz) && memcmp((c)+12, (data), (dsz)) == 0)
870 #define rrTTL(c) ((c)+6)
871
872 for(;;) {
873 if (!hasRR(c,e))
874 return ttl;
875 if (sameRRT(c,dtp1,dtp2))
876 break;
877 c = nextRR(c);
878 }
879
880 /* found at least one RR with the same type as new */
881
882 if (ttl >= (t = unpack32(rrTTL(c)))) {
883 /* new ttl is either larger or the same as ttl of one of existing RRs */
884 /* if we already have the same record, do nothing */
885 if (sameDATA(c,dsz,data))
886 return 0;
887 /* check other records too */
888 for(c = nextRR(c); hasRR(c,e); c = nextRR(c))
889 if (sameRRT(c,dtp1,dtp2) && sameDATA(c,dsz,data))
890 /* already has exactly the same data */
891 return 0;
892 return t; /* use existing, smaller TTL for new RR */
893 }
894 else { /* change TTLs of existing RRs to new, smaller one */
895 int same = sameDATA(c,dsz,data);
896 unsigned char *ttlnb = rrTTL(c);
897 PACK32(ttlnb, ttl);
898 for(c = nextRR(c); hasRR(c,e); c = nextRR(c))
899 if (sameRRT(c,dtp1,dtp2)) {
900 memcpy(rrTTL(c), ttlnb, 4);
901 if (sameDATA(c,dsz,data))
902 same = 1;
903 }
904 return same ? 0 : ttl;
905 }
906 #undef nextRR
907 #undef hasRR
908 #undef sameRRT
909 #undef sameDATA
910 #undef rrTTL
911 }
912
913 /* add a new record into answer, check for dups.
914 * We just ignore any data that exceeds packet size */
addrr_any(struct dnspacket * pkt,unsigned dtp,const void * data,unsigned dsz,unsigned ttl)915 void addrr_any(struct dnspacket *pkt, unsigned dtp,
916 const void *data, unsigned dsz,
917 unsigned ttl) {
918 register unsigned char *c = pkt->p_cur;
919 ttl = checkrr_present(pkt->p_sans, c, dtp, data, dsz, ttl);
920 if (!ttl) return; /* if RR is already present, do nothing */
921
922 if (!fit(pkt, c, 12 + dsz) || pkt->p_buf[p_ancnt2] == 255) {
923 setnonauth(pkt->p_buf); /* non-auth answer as we can't fit the record */
924 return;
925 }
926 *c++ = 192; *c++ = p_hdrsize; /* jump after header: query DN */
927 PACK16S(c, dtp);
928 PACK16S(c, DNS_C_IN);
929 PACK32S(c, ttl);
930 PACK16S(c, dsz);
931 memcpy(c, data, dsz);
932 pkt->p_cur = c + dsz;
933 pkt->p_buf[p_ancnt2] += 1; /* increment numanswers */
934 }
935
936 void
addrr_a_txt(struct dnspacket * pkt,unsigned qtflag,const char * rr,const char * subst,const struct dataset * ds)937 addrr_a_txt(struct dnspacket *pkt, unsigned qtflag,
938 const char *rr, const char *subst,
939 const struct dataset *ds) {
940 if (qtflag & NSQUERY_A)
941 addrr_any(pkt, DNS_T_A, rr, 4, ds->ds_ttl);
942 if (qtflag & NSQUERY_TXT) {
943 char sb[TXTBUFSIZ+1];
944 unsigned sl = txtsubst(sb + 1, rr + 4, subst, ds);
945 if (sl) {
946 sb[0] = sl;
947 addrr_any(pkt, DNS_T_TXT, sb, sl + 1, ds->ds_ttl);
948 }
949 }
950 }
951
version_req(struct dnspacket * pkt,const struct dnsquery * qry)952 static int version_req(struct dnspacket *pkt, const struct dnsquery *qry) {
953 register unsigned char *c;
954 unsigned dsz;
955
956 if (!show_version)
957 return 0;
958 if (qry->q_class != DNS_C_CH || qry->q_type != DNS_T_TXT)
959 return 0;
960 if ((qry->q_dnlen != 16 || memcmp(qry->q_dn, "\7version\6server", 16)) &&
961 (qry->q_dnlen != 14 || memcmp(qry->q_dn, "\7version\4bind", 14)))
962 return 0;
963
964 c = pkt->p_cur;
965 *c++ = 192; *c++ = p_hdrsize; /* jump after header: query DN */
966 *c++ = DNS_T_TXT>>8; *c++ = DNS_T_TXT;
967 *c++ = DNS_C_CH>>8; *c++ = DNS_C_CH;
968 *c++ = 0; *c++ = 0; *c++ = 0; *c++ = 0; /* ttl */
969 dsz = strlen(show_version) + 1;
970 PACK16(c, dsz); c += 2; /* dsize */
971 *c++ = --dsz;
972 memcpy(c, show_version, dsz);
973 pkt->p_cur = c + dsz;
974 pkt->p_buf[p_ancnt2] += 1; /* increment numanswers */
975 return 1;
976 }
977
logreply(const struct dnspacket * pkt,FILE * flog,int flushlog)978 void logreply(const struct dnspacket *pkt, FILE *flog, int flushlog) {
979 char cbuf[DNS_MAXDOMAIN + IPSIZE + 50];
980 char *cp = cbuf;
981 const unsigned char *const q = pkt->p_sans - 4;
982
983 cp += sprintf(cp, "%lu ", (unsigned long)time(NULL));
984 #ifndef NO_IPv6
985 if (getnameinfo(pkt->p_peer, pkt->p_peerlen,
986 cp, NI_MAXHOST, NULL, 0,
987 NI_NUMERICHOST) == 0)
988 cp += strlen(cp);
989 else
990 *cp++ = '?';
991 #else
992 strcpy(cp, inet_ntoa(((struct sockaddr_in*)pkt->p_peer)->sin_addr));
993 cp += strlen(cp);
994 #endif
995 *cp++ = ' ';
996 cp += dns_dntop(pkt->p_buf + p_hdrsize, cp, DNS_MAXDOMAIN);
997 cp += sprintf(cp, " %s %s: %s/%u/%d\n",
998 dns_typename(((unsigned)q[0]<<8)|q[1]),
999 dns_classname(((unsigned)q[2]<<8)|q[3]),
1000 dns_rcodename(pkt->p_buf[p_f2] & pf2_rcode),
1001 pkt->p_buf[p_ancnt2], (int)(pkt->p_cur - pkt->p_buf));
1002 if (flushlog)
1003 write(fileno(flog), cbuf, cp - cbuf);
1004 else
1005 fwrite(cbuf, cp - cbuf, 1, flog);
1006 }
1007