Blob


1 /*
2 * Copyright (c) 2005-2014 Peter J. Philipp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28 #include "include.h"
29 #include "dns.h"
30 #include "db.h"
32 /* prototypes */
34 extern int additional_a(char *, int, struct domain *, char *, int, int, int *);
35 extern int additional_aaaa(char *, int, struct domain *, char *, int, int, int *);
36 extern int additional_mx(char *, int, struct domain *, char *, int, int, int *);
37 extern int additional_ptr(char *, int, struct domain *, char *, int, int, int *);
38 extern int additional_opt(struct question *, char *, int, int);
39 extern struct question *build_fake_question(char *, int, u_int16_t);
40 extern int compress_label(u_char *, int, int);
41 extern void dolog(int, char *, ...);
42 extern int free_question(struct question *);
43 extern int lookup_zone(DB *, struct question *, struct domain *, int *, char *, int);
44 extern void slave_shutdown(void);
47 struct domain *Lookup_zone(DB *, char *, u_int16_t, u_int16_t, int);
48 void collects_init(void);
49 u_int16_t create_anyreply(struct sreply *, char *, int, int, int);
50 u_short in_cksum(const u_short *, register int, int);
51 int reply_a(struct sreply *, DB *);
52 int reply_aaaa(struct sreply *, DB *);
53 int reply_mx(struct sreply *, DB *);
54 int reply_ns(struct sreply *, DB *);
55 int reply_notimpl(struct sreply *);
56 int reply_nxdomain(struct sreply *);
57 int reply_noerror(struct sreply *);
58 int reply_soa(struct sreply *);
59 int reply_ptr(struct sreply *);
60 int reply_txt(struct sreply *);
61 int reply_spf(struct sreply *);
62 int reply_srv(struct sreply *, DB *);
63 int reply_naptr(struct sreply *, DB *);
64 int reply_sshfp(struct sreply *);
65 int reply_cname(struct sreply *);
66 int reply_any(struct sreply *);
67 int reply_refused(struct sreply *);
68 int reply_fmterror(struct sreply *);
69 int reply_raw2(int, char *, int, struct recurses *);
70 int reply_raw6(int, char *, int, struct recurses *);
71 void update_db(DB *, struct domain *);
73 #ifdef __linux__
74 static int udp_cksum(const struct iphdr *, const struct udphdr *, int);
75 #else
76 static int udp_cksum(const struct ip *, const struct udphdr *, int);
77 #endif
79 SLIST_HEAD(listhead, collects) collectshead;
81 struct collects {
82 char *name;
83 u_int16_t namelen;
84 u_int16_t type;
85 struct domain *sd;
86 SLIST_ENTRY(collects) collect_entry;
87 } *cn1, *cn2, *cnp;
89 extern int debug, verbose;
92 static const char rcsid[] = "$Id: reply.c,v 1.60 2014/10/08 21:00:55 pjp Exp $";
94 /*
95 * REPLY_A() - replies a DNS question (*q) on socket (so)
96 *
97 */
99 int
100 reply_a(struct sreply *sreply, DB *db)
102 char *reply = sreply->replybuf;
103 struct dns_header *odh;
104 u_int16_t outlen;
105 int a_count;
106 int mod, pos;
107 int ttlhack = 0;
109 struct answer {
110 char name[2];
111 u_int16_t type;
112 u_int16_t class;
113 u_int32_t ttl;
114 u_int16_t rdlength; /* 12 */
115 in_addr_t rdata; /* 16 */
116 } __attribute__((packed));
118 struct answer *answer;
120 int so = sreply->so;
121 char *buf = sreply->buf;
122 int len = sreply->len;
123 struct question *q = sreply->q;
124 struct sockaddr *sa = sreply->sa;
125 int salen = sreply->salen;
126 struct domain *sd = sreply->sd1;
128 u_int8_t region = sreply->region;
129 int istcp = sreply->istcp;
130 int replysize = 512;
131 int retlen = -1;
133 if (istcp) {
134 replysize = 65535;
137 if (q->edns0len > 512)
138 replysize = q->edns0len;
140 odh = (struct dns_header *)&reply[0];
142 outlen = sizeof(struct dns_header);
144 if (len > replysize) {
145 return (retlen);
148 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
149 memset((char *)&odh->query, 0, sizeof(u_int16_t));
151 outlen += (q->hdr->namelen + 4);
153 SET_DNS_REPLY(odh);
154 if (sreply->sr == NULL)
155 SET_DNS_AUTHORITATIVE(odh);
156 else
157 SET_DNS_RECURSION_AVAIL(odh);
159 HTONS(odh->query);
161 odh->question = htons(1);
162 odh->answer = htons(sd->a_count);
163 odh->nsrr = 0;
164 odh->additional = 0;
166 /* skip dns header, question name, qtype and qclass */
167 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
168 q->hdr->namelen + 4);
170 /* if we aren't a balance record our region code is 0xff so check */
171 if (sd->region[sd->a_ptr] != 0xff) {
172 ttlhack = 1;
175 a_count = 0;
176 pos = sd->a_ptr;
177 mod = sd->a_count;
179 do {
180 /*
181 * skip records that are not in the needed region
182 */
183 if (ttlhack && sd->region[pos % mod] != region) {
184 pos++;
185 continue;
188 /*
189 * answer->name is a pointer to the request (0xc00c)
190 */
192 answer->name[0] = 0xc0; /* 1 byte */
193 answer->name[1] = 0x0c; /* 2 bytes */
194 answer->type = q->hdr->qtype; /* 4 bytes */
195 answer->class = q->hdr->qclass; /* 6 bytes */
196 if (sreply->sr != NULL)
197 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
198 else
199 answer->ttl = htonl(sd->ttl); /* 10 bytes */
201 answer->rdlength = htons(sizeof(in_addr_t)); /* 12 bytes */
203 memcpy((char *)&answer->rdata, (char *)&sd->a[pos++ % mod],
204 sizeof(in_addr_t)); /* 16 bytes */
206 a_count++;
207 outlen += 16;
209 /* can we afford to write another header? if no truncate */
210 if (sd->a_count > 1 && outlen + 16 > replysize) {
211 NTOHS(odh->query);
212 SET_DNS_TRUNCATION(odh);
213 HTONS(odh->query);
214 goto out;
218 /* set new offset for answer */
219 answer = (struct answer *)&reply[outlen];
220 } while (a_count < RECORD_COUNT && --sd->a_count);
222 if (ttlhack) {
223 odh->answer = htons(a_count);
226 if (q->edns0len) {
227 /* tag on edns0 opt record */
228 odh->additional = htons(1);
229 outlen = additional_opt(q, reply, replysize, outlen);
232 out:
233 if (sreply->sr != NULL) {
234 retlen = reply_raw2(so, reply, outlen, sreply->sr);
235 } else {
236 if (istcp) {
237 char *tmpbuf;
238 u_int16_t *plen;
240 tmpbuf = malloc(outlen + 2);
241 if (tmpbuf == NULL) {
242 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
244 plen = (u_int16_t *)tmpbuf;
245 *plen = htons(outlen);
247 memcpy(&tmpbuf[2], reply, outlen);
249 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
250 dolog(LOG_INFO, "send: %s\n", strerror(errno));
252 free(tmpbuf);
253 } else {
254 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
255 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
259 } /* if (->sr) */
260 /*
261 * update a_ptr setting
262 */
264 sd->a_ptr = (sd->a_ptr + 1) % mod;
265 sd->a_count = mod; /* I know I know */
266 update_db(db, sd);
268 return (retlen);
271 /*
272 * REPLY_AAAA() - replies a DNS question (*q) on socket (so)
274 */
276 int
277 reply_aaaa(struct sreply *sreply, DB *db)
279 char *reply = sreply->replybuf;
280 struct dns_header *odh;
281 u_int16_t outlen;
282 int aaaa_count;
283 int mod, pos;
285 struct answer {
286 char name[2];
287 u_int16_t type;
288 u_int16_t class;
289 u_int32_t ttl;
290 u_int16_t rdlength; /* 12 */
291 char rdata; /* 12 + 16 */
292 } __attribute__((packed));
294 struct answer *answer;
296 int so = sreply->so;
297 char *buf = sreply->buf;
298 int len = sreply->len;
299 struct question *q = sreply->q;
300 struct sockaddr *sa = sreply->sa;
301 int salen = sreply->salen;
302 struct domain *sd = sreply->sd1;
303 int istcp = sreply->istcp;
304 int replysize = 512;
305 int retlen = -1;
307 if (istcp) {
308 replysize = 65535;
311 if (q->edns0len > 512)
312 replysize = q->edns0len;
315 odh = (struct dns_header *)&reply[0];
317 outlen = sizeof(struct dns_header);
319 if (len > replysize) {
320 return (retlen);
323 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
324 memset((char *)&odh->query, 0, sizeof(u_int16_t));
326 outlen += (q->hdr->namelen + 4);
328 SET_DNS_REPLY(odh);
329 if (sreply->sr == NULL)
330 SET_DNS_AUTHORITATIVE(odh);
331 else
332 SET_DNS_RECURSION_AVAIL(odh);
334 HTONS(odh->query);
336 odh->question = htons(1);
337 odh->answer = htons(sd->aaaa_count);
338 odh->nsrr = 0;
339 odh->additional = 0;
341 /* skip dns header, question name, qtype and qclass */
342 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
343 q->hdr->namelen + 4);
346 aaaa_count = 0;
347 pos = sd->aaaa_ptr;
348 mod = sd->aaaa_count;
350 do {
351 answer->name[0] = 0xc0;
352 answer->name[1] = 0x0c;
353 answer->type = q->hdr->qtype;
354 answer->class = q->hdr->qclass;
355 if (sreply->sr != NULL)
356 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
357 else
358 answer->ttl = htonl(sd->ttl); /* 10 bytes */
360 answer->rdlength = htons(sizeof(struct in6_addr));
362 memcpy((char *)&answer->rdata, (char *)&sd->aaaa[pos++ % mod], sizeof(struct in6_addr));
363 outlen += 28;
365 /* can we afford to write another header? if no truncate */
366 if (sd->aaaa_count > 1 && outlen + 28 > replysize) {
367 NTOHS(odh->query);
368 SET_DNS_TRUNCATION(odh);
369 HTONS(odh->query);
370 goto out;
373 aaaa_count++;
375 /* set new offset for answer */
376 answer = (struct answer *)&reply[outlen];
377 } while (aaaa_count < RECORD_COUNT && --sd->aaaa_count);
379 if (q->edns0len) {
380 /* tag on edns0 opt record */
381 odh->additional = htons(1);
382 outlen = additional_opt(q, reply, replysize, outlen);
385 out:
386 if (sreply->sr != NULL) {
387 retlen = reply_raw2(so, reply, outlen, sreply->sr);
388 } else {
389 if (istcp) {
390 char *tmpbuf;
391 u_int16_t *plen;
393 tmpbuf = malloc(outlen + 2);
394 if (tmpbuf == NULL) {
395 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
397 plen = (u_int16_t *)tmpbuf;
398 *plen = htons(outlen);
400 memcpy(&tmpbuf[2], reply, outlen);
402 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
403 dolog(LOG_INFO, "send: %s\n", strerror(errno));
405 free(tmpbuf);
406 } else {
407 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
408 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
413 sd->aaaa_ptr = (sd->aaaa_ptr + 1) % mod;
414 sd->aaaa_count = mod;
415 update_db(db, sd);
417 return (retlen);
420 /*
421 * REPLY_MX() - replies a DNS question (*q) on socket (so)
423 */
425 int
426 reply_mx(struct sreply *sreply, DB *db)
428 char *reply = sreply->replybuf;
429 struct dns_header *odh;
430 struct domain *sd0;
431 int mx_count;
432 u_int16_t *plen;
433 char *name;
434 u_int16_t outlen;
435 u_int16_t namelen;
436 int additional = 0;
438 struct answer {
439 char name[2];
440 u_int16_t type;
441 u_int16_t class;
442 u_int32_t ttl;
443 u_int16_t rdlength; /* 12 */
444 u_int16_t mx_priority;
445 char exchange;
446 } __attribute__((packed));
448 struct answer *answer;
450 int so = sreply->so;
451 char *buf = sreply->buf;
452 int len = sreply->len;
453 struct question *q = sreply->q;
454 struct sockaddr *sa = sreply->sa;
455 int salen = sreply->salen;
456 struct domain *sd = sreply->sd1;
457 int istcp = sreply->istcp;
458 int wildcard = sreply->wildcard;
459 int replysize = 512;
460 int retlen = -1;
462 if (istcp) {
463 replysize = 65535;
466 if (q->edns0len > 512)
467 replysize = q->edns0len;
469 odh = (struct dns_header *)&reply[0];
471 outlen = sizeof(struct dns_header);
473 if (len > replysize) {
474 return (retlen);
477 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
478 memset((char *)&odh->query, 0, sizeof(u_int16_t));
480 outlen += (q->hdr->namelen + 4);
482 SET_DNS_REPLY(odh);
484 if (sreply->sr == NULL) {
485 SET_DNS_AUTHORITATIVE(odh);
486 } else
487 SET_DNS_RECURSION_AVAIL(odh);
489 HTONS(odh->query);
491 odh->question = htons(1);
492 odh->answer = htons(sd->mx_count);
493 odh->nsrr = 0;
494 odh->additional = 0;
496 /* skip dns header, question name, qtype and qclass */
497 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
498 q->hdr->namelen + 4);
500 mx_count = 0;
501 do {
502 answer->name[0] = 0xc0;
503 answer->name[1] = 0x0c;
504 answer->type = q->hdr->qtype;
505 answer->class = q->hdr->qclass;
506 if (sreply->sr != NULL)
507 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
508 else
509 answer->ttl = htonl(sd->ttl);
511 answer->rdlength = htons(sizeof(u_int16_t) + sd->mx[mx_count].exchangelen);
513 answer->mx_priority = htons(sd->mx[mx_count].preference);
514 memcpy((char *)&answer->exchange, (char *)sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
516 name = sd->mx[mx_count].exchange;
517 namelen = sd->mx[mx_count].exchangelen;
519 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_A), wildcard);
520 if (sd0 != NULL) {
521 cn1 = malloc(sizeof(struct collects));
522 if (cn1 != NULL) {
523 cn1->name = malloc(namelen);
524 if (cn1->name != NULL) {
525 memcpy(cn1->name, name, namelen);
526 cn1->namelen = namelen;
527 cn1->sd = sd0;
528 cn1->type = DNS_TYPE_A;
530 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
534 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_AAAA), wildcard);
535 if (sd0 != NULL) {
536 cn1 = malloc(sizeof(struct collects));
537 if (cn1 != NULL) {
538 cn1->name = malloc(namelen);
539 if (cn1->name != NULL) {
540 memcpy(cn1->name, name, namelen);
541 cn1->namelen = namelen;
542 cn1->sd = sd0;
543 cn1->type = DNS_TYPE_AAAA;
545 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
550 outlen += (12 + 2 + sd->mx[mx_count].exchangelen);
552 /* can we afford to write another header? if no truncate */
553 if (sd->mx_count > 1 && (outlen + 12 + 2 + sd->mx[mx_count].exchangelen) > replysize) {
554 NTOHS(odh->query);
555 SET_DNS_TRUNCATION(odh);
556 HTONS(odh->query);
557 goto out;
560 /* set new offset for answer */
561 answer = (struct answer *)&reply[outlen];
562 } while (++mx_count < RECORD_COUNT && --sd->mx_count);
564 /* write additional */
566 SLIST_FOREACH(cnp, &collectshead, collect_entry) {
567 int addcount;
568 int tmplen;
570 switch (cnp->type) {
571 case DNS_TYPE_A:
572 tmplen = additional_a(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
573 additional += addcount;
574 break;
575 case DNS_TYPE_AAAA:
576 tmplen = additional_aaaa(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
577 additional += addcount;
578 break;
581 if (tmplen > 0) {
582 outlen = tmplen;
586 odh->additional = htons(additional);
588 while (!SLIST_EMPTY(&collectshead)) {
589 cn1 = SLIST_FIRST(&collectshead);
590 SLIST_REMOVE_HEAD(&collectshead, collect_entry);
591 free(cn1->name);
592 free(cn1->sd);
593 free(cn1);
596 if (q->edns0len) {
597 /* tag on edns0 opt record */
598 NTOHS(odh->additional);
599 odh->additional++;
600 HTONS(odh->additional);
602 outlen = additional_opt(q, reply, replysize, outlen);
605 out:
606 if (sreply->sr != NULL) {
607 retlen = reply_raw2(so, reply, outlen, sreply->sr);
608 } else {
609 if (istcp) {
610 char *tmpbuf;
612 tmpbuf = malloc(outlen + 2);
613 if (tmpbuf == NULL) {
614 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
616 plen = (u_int16_t *)tmpbuf;
617 *plen = htons(outlen);
619 memcpy(&tmpbuf[2], reply, outlen);
620 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
621 dolog(LOG_INFO, "send: %s\n", strerror(errno));
623 free(tmpbuf);
624 } else {
625 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
626 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
631 return (retlen);
634 /*
635 * REPLY_NS() - replies a DNS question (*q) on socket (so)
637 */
639 int
640 reply_ns(struct sreply *sreply, DB *db)
642 char *reply = sreply->replybuf;
643 struct dns_header *odh;
644 struct domain *sd0;
645 int tmplen;
646 int ns_count;
647 int mod, pos;
648 u_int16_t *plen;
649 char *name;
650 u_int16_t outlen;
651 u_int16_t namelen;
652 int additional = 0;
654 struct answer {
655 char name[2];
656 u_int16_t type;
657 u_int16_t class;
658 u_int32_t ttl;
659 u_int16_t rdlength; /* 12 */
660 char ns;
661 } __attribute__((packed));
663 struct answer *answer;
665 int so = sreply->so;
666 char *buf = sreply->buf;
667 int len = sreply->len;
668 struct question *q = sreply->q;
669 struct sockaddr *sa = sreply->sa;
670 int salen = sreply->salen;
671 struct domain *sd = sreply->sd1;
672 int istcp = sreply->istcp;
673 int wildcard = sreply->wildcard;
674 int replysize = 512;
675 int retlen = -1;
677 if (istcp) {
678 replysize = 65535;
681 if (q->edns0len > 512)
682 replysize = q->edns0len;
684 odh = (struct dns_header *)&reply[0];
686 outlen = sizeof(struct dns_header);
688 if (len > replysize) {
689 return (retlen);
692 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
694 memset((char *)&odh->query, 0, sizeof(u_int16_t));
696 outlen += (q->hdr->namelen + 4);
698 SET_DNS_REPLY(odh);
700 if (sreply->sr == NULL) {
701 switch (sd->ns_type) {
702 case 0:
703 SET_DNS_AUTHORITATIVE(odh);
704 break;
705 default:
706 SET_DNS_RECURSION(odh);
707 break;
709 } else
710 SET_DNS_RECURSION_AVAIL(odh);
713 HTONS(odh->query);
715 odh->question = htons(1);
716 switch (sd->ns_type) {
717 case NS_TYPE_DELEGATE:
718 odh->answer = 0;
719 odh->nsrr = htons(sd->ns_count);
720 break;
721 default:
722 odh->answer = htons(sd->ns_count);
723 odh->nsrr = 0;
724 break;
726 odh->additional = 0;
728 /* skip dns header, question name, qtype and qclass */
729 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
730 q->hdr->namelen + 4);
732 ns_count = 0;
733 mod = sd->ns_count;
734 pos = sd->ns_ptr;
736 do {
737 answer->name[0] = 0xc0;
738 answer->name[1] = 0x0c;
739 answer->type = htons(DNS_TYPE_NS);
740 answer->class = q->hdr->qclass;
741 if (sreply->sr != NULL)
742 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
743 else
744 answer->ttl = htonl(sd->ttl);
746 name = sd->ns[pos % mod].nsserver;
747 namelen = sd->ns[pos % mod].nslen;
749 answer->rdlength = htons(namelen);
751 memcpy((char *)&answer->ns, (char *)name, namelen);
753 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_A), wildcard);
754 if (sd0 != NULL) {
755 cn1 = malloc(sizeof(struct collects));
756 if (cn1 != NULL) {
757 cn1->name = malloc(namelen);
758 if (cn1->name != NULL) {
759 memcpy(cn1->name, name, namelen);
760 cn1->namelen = namelen;
761 cn1->sd = sd0;
762 cn1->type = DNS_TYPE_A;
764 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
769 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_AAAA), wildcard);
770 if (sd0 != NULL) {
771 cn1 = malloc(sizeof(struct collects));
772 if (cn1 != NULL) {
773 cn1->name = malloc(namelen);
774 if (cn1->name != NULL) {
775 memcpy(cn1->name, name, namelen);
776 cn1->namelen = namelen;
777 cn1->sd = sd0;
778 cn1->type = DNS_TYPE_AAAA;
780 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
787 outlen += (12 + namelen);
789 /* compress the label if possible */
790 if ((tmplen = compress_label((u_char*)reply, outlen, namelen)) > 0) {
791 /* XXX */
792 outlen = tmplen;
795 answer->rdlength = htons(&reply[outlen] - &answer->ns);
798 /* can we afford to write another header? if no truncate */
799 if (sd->ns_count > 1 && (outlen + 12 + sd->ns[pos % mod].nslen) > replysize) {
800 NTOHS(odh->query);
801 SET_DNS_TRUNCATION(odh);
802 HTONS(odh->query);
803 goto out;
806 pos++;
807 /* set new offset for answer */
808 answer = (struct answer *)&reply[outlen];
809 } while (++ns_count < RECORD_COUNT && --sd->ns_count);
811 /* shuffle through our linked collect structure and add additional */
813 SLIST_FOREACH(cnp, &collectshead, collect_entry) {
814 int addcount;
815 int tmplen;
817 switch (cnp->type) {
818 case DNS_TYPE_A:
819 tmplen = additional_a(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
820 additional += addcount;
821 break;
822 case DNS_TYPE_AAAA:
823 tmplen = additional_aaaa(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
824 additional += addcount;
825 break;
828 if (tmplen > 0) {
829 outlen = tmplen;
833 odh->additional = htons(additional);
835 while (!SLIST_EMPTY(&collectshead)) {
836 cn1 = SLIST_FIRST(&collectshead);
837 SLIST_REMOVE_HEAD(&collectshead, collect_entry);
838 free(cn1->name);
839 free(cn1->sd);
840 free(cn1);
843 if (q->edns0len) {
844 /* tag on edns0 opt record */
845 NTOHS(odh->additional);
846 odh->additional++;
847 HTONS(odh->additional);
849 outlen = additional_opt(q, reply, replysize, outlen);
852 out:
853 if (sreply->sr != NULL) {
854 retlen = reply_raw2(so, reply, outlen, sreply->sr);
855 } else {
856 if (istcp) {
857 char *tmpbuf;
859 tmpbuf = malloc(outlen + 2);
860 if (tmpbuf == NULL) {
861 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
863 plen = (u_int16_t *)tmpbuf;
864 *plen = htons(outlen);
866 memcpy(&tmpbuf[2], reply, outlen);
867 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
868 dolog(LOG_INFO, "send: %s\n", strerror(errno));
870 free(tmpbuf);
871 } else {
872 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
873 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
878 sd->ns_ptr = (sd->ns_ptr + 1) % mod;
879 sd->ns_count = mod;
881 update_db(db, sd);
883 return (retlen);
887 /*
888 * REPLY_CNAME() - replies a DNS question (*q) on socket (so)
890 */
893 int
894 reply_cname(struct sreply *sreply)
896 char *reply = sreply->replybuf;
897 struct dns_header *odh;
898 u_int16_t outlen;
899 char *p;
900 int i, tmplen;
901 int labellen;
902 char *label, *plabel;
903 int addcount;
904 u_int16_t *plen;
906 struct answer {
907 char name[2];
908 u_int16_t type;
909 u_int16_t class;
910 u_int32_t ttl;
911 u_int16_t rdlength; /* 12 */
912 char rdata;
913 } __attribute__((packed));
915 struct answer *answer;
917 int so = sreply->so;
918 char *buf = sreply->buf;
919 int len = sreply->len;
920 struct question *q = sreply->q;
921 struct sockaddr *sa = sreply->sa;
922 int salen = sreply->salen;
923 struct domain *sd = sreply->sd1;
924 struct domain *sd1 = sreply->sd2;
925 int istcp = sreply->istcp;
926 int replysize = 512;
927 int retlen = -1;
929 if (istcp) {
930 replysize = 65535;
933 if (q->edns0len > 512)
934 replysize = q->edns0len;
936 odh = (struct dns_header *)&reply[0];
937 outlen = sizeof(struct dns_header);
939 if (len > replysize) {
940 return (retlen);
943 /* copy question to reply */
944 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
946 /* blank query */
947 memset((char *)&odh->query, 0, sizeof(u_int16_t));
949 outlen += (q->hdr->namelen + 4);
951 SET_DNS_REPLY(odh);
952 if (sreply->sr == NULL)
953 SET_DNS_AUTHORITATIVE(odh);
954 else
955 SET_DNS_RECURSION_AVAIL(odh);
957 HTONS(odh->query);
959 odh->question = htons(1);
960 odh->answer = htons(1);
961 odh->nsrr = 0;
962 odh->additional = 0;
964 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
965 q->hdr->namelen + 4);
967 answer->name[0] = 0xc0;
968 answer->name[1] = 0x0c;
969 answer->type = htons(DNS_TYPE_CNAME);
970 answer->class = q->hdr->qclass;
971 if (sreply->sr != NULL)
972 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
973 else
974 answer->ttl = htonl(sd->ttl);
976 outlen += 12; /* up to rdata length */
978 p = (char *)&answer->rdata;
980 label = &sd->cname[0];
981 labellen = sd->cnamelen;
983 plabel = label;
985 /* copy label to reply */
986 for (i = outlen; i < replysize; i++) {
987 if (i - outlen == labellen)
988 break;
990 reply[i] = *plabel++;
993 if (i >= replysize)
994 return (retlen);
996 outlen = i;
998 /* compress the label if possible */
999 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
1000 /* XXX */
1001 outlen = tmplen;
1004 answer->rdlength = htons(&reply[outlen] - &answer->rdata);
1007 if (ntohs(q->hdr->qtype) == DNS_TYPE_A && sd1 != NULL) {
1008 tmplen = additional_a(sd->cname, sd->cnamelen, sd1, reply, replysize, outlen, &addcount);
1010 if (tmplen > 0)
1011 outlen = tmplen;
1013 NTOHS(odh->answer);
1014 odh->answer += addcount;
1015 HTONS(odh->answer);
1016 } else if (ntohs(q->hdr->qtype) == DNS_TYPE_AAAA && sd1 != NULL) {
1017 tmplen = additional_aaaa(sd->cname, sd->cnamelen, sd1, reply, replysize, outlen, &addcount);
1019 if (tmplen > 0)
1020 outlen = tmplen;
1022 NTOHS(odh->answer);
1023 odh->answer += addcount;
1024 HTONS(odh->answer);
1025 } else if (ntohs(q->hdr->qtype) == DNS_TYPE_MX && sd1 != NULL) {
1026 tmplen = additional_mx(sd->cname, sd->cnamelen, sd1, reply, replysize, outlen, &addcount);
1028 if (tmplen > 0)
1029 outlen = tmplen;
1031 NTOHS(odh->answer);
1032 odh->answer += addcount;
1033 HTONS(odh->answer);
1034 } else if (ntohs(q->hdr->qtype) == DNS_TYPE_PTR && sd1 != NULL) {
1035 tmplen = additional_ptr(sd->cname, sd->cnamelen, sd1, reply, replysize, outlen, &addcount);
1037 if (tmplen > 0)
1038 outlen = tmplen;
1040 NTOHS(odh->answer);
1041 odh->answer += addcount;
1042 HTONS(odh->answer);
1045 if (q->edns0len) {
1046 /* tag on edns0 opt record */
1047 NTOHS(odh->additional);
1048 odh->additional++;
1049 HTONS(odh->additional);
1051 outlen = additional_opt(q, reply, replysize, outlen);
1054 if (sreply->sr != NULL) {
1055 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1056 } else {
1057 if (istcp) {
1058 char *tmpbuf;
1060 tmpbuf = malloc(outlen + 2);
1061 if (tmpbuf == NULL) {
1062 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1064 plen = (u_int16_t *)tmpbuf;
1065 *plen = htons(outlen);
1067 memcpy(&tmpbuf[2], reply, outlen);
1069 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1070 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1072 free(tmpbuf);
1073 } else {
1074 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1075 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1080 return (retlen);
1084 * REPLY_PTR() - replies a DNS question (*q) on socket (so)
1088 int
1089 reply_ptr(struct sreply *sreply)
1091 char *reply = sreply->replybuf;
1092 struct dns_header *odh;
1093 u_int16_t outlen;
1094 char *p;
1095 int i, tmplen;
1096 int labellen;
1097 char *label, *plabel;
1099 struct answer {
1100 char name[2];
1101 u_int16_t type;
1102 u_int16_t class;
1103 u_int32_t ttl;
1104 u_int16_t rdlength; /* 12 */
1105 char rdata;
1106 } __attribute__((packed));
1108 struct answer *answer;
1110 int so = sreply->so;
1111 char *buf = sreply->buf;
1112 int len = sreply->len;
1113 struct question *q = sreply->q;
1114 struct sockaddr *sa = sreply->sa;
1115 int salen = sreply->salen;
1116 struct domain *sd = sreply->sd1;
1117 int istcp = sreply->istcp;
1118 int replysize = 512;
1119 int retlen = -1;
1121 if (istcp) {
1122 replysize = 65535;
1125 if (q->edns0len > 512)
1126 replysize = q->edns0len;
1128 odh = (struct dns_header *)&reply[0];
1129 outlen = sizeof(struct dns_header);
1132 if (len > replysize) {
1133 return (retlen);
1136 /* copy question to reply */
1137 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1138 /* blank query */
1139 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1141 outlen += (q->hdr->namelen + 4);
1143 SET_DNS_REPLY(odh);
1144 if (sreply->sr == NULL)
1145 SET_DNS_AUTHORITATIVE(odh);
1146 else
1147 SET_DNS_RECURSION_AVAIL(odh);
1149 HTONS(odh->query);
1151 odh->question = htons(1);
1152 odh->answer = htons(1);
1153 odh->nsrr = 0;
1154 odh->additional = 0;
1156 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1157 q->hdr->namelen + 4);
1159 answer->name[0] = 0xc0;
1160 answer->name[1] = 0x0c;
1161 answer->type = q->hdr->qtype;
1162 answer->class = q->hdr->qclass;
1163 if (sreply->sr != NULL)
1164 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1165 else
1166 answer->ttl = htonl(sd->ttl);
1168 outlen += 12; /* up to rdata length */
1170 p = (char *)&answer->rdata;
1172 label = &sd->ptr[0];
1173 labellen = sd->ptrlen;
1175 plabel = label;
1177 /* copy label to reply */
1178 for (i = outlen; i < replysize; i++) {
1179 if (i - outlen == labellen)
1180 break;
1182 reply[i] = *plabel++;
1185 if (i >= replysize) {
1186 return (retlen);
1189 outlen = i;
1191 /* compress the label if possible */
1192 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
1193 outlen = tmplen;
1196 answer->rdlength = htons(&reply[outlen] - &answer->rdata);
1198 if (q->edns0len) {
1199 /* tag on edns0 opt record */
1200 NTOHS(odh->additional);
1201 odh->additional++;
1202 HTONS(odh->additional);
1204 outlen = additional_opt(q, reply, replysize, outlen);
1207 if (sreply->sr != NULL) {
1208 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1209 } else {
1210 if (istcp) {
1211 char *tmpbuf;
1212 u_int16_t *plen;
1214 tmpbuf = malloc(outlen + 2);
1215 if (tmpbuf == NULL) {
1216 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1218 plen = (u_int16_t *)tmpbuf;
1219 *plen = htons(outlen);
1221 memcpy(&tmpbuf[2], reply, outlen);
1223 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1224 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1226 free(tmpbuf);
1227 } else {
1228 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1229 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1234 return (retlen);
1238 * REPLY_SOA() - replies a DNS question (*q) on socket (so)
1243 int
1244 reply_soa(struct sreply *sreply)
1246 char *reply = sreply->replybuf;
1247 struct dns_header *odh;
1248 u_int16_t outlen;
1249 char *p;
1250 u_int32_t *soa_val;
1251 int i, tmplen;
1252 int labellen;
1253 char *label, *plabel;
1255 struct answer {
1256 char name[2];
1257 u_int16_t type;
1258 u_int16_t class;
1259 u_int32_t ttl;
1260 u_int16_t rdlength; /* 12 */
1261 char rdata;
1262 } __attribute__((packed));
1264 struct soa {
1265 char *nsserver;
1266 char *responsible_person;
1267 u_int32_t serial;
1268 u_int32_t refresh;
1269 u_int32_t retry;
1270 u_int32_t expire;
1271 u_int32_t minttl;
1275 struct answer *answer;
1277 int so = sreply->so;
1278 char *buf = sreply->buf;
1279 int len = sreply->len;
1280 struct question *q = sreply->q;
1281 struct sockaddr *sa = sreply->sa;
1282 int salen = sreply->salen;
1283 struct domain *sd = sreply->sd1;
1284 int istcp = sreply->istcp;
1285 int replysize = 512;
1286 int retlen = -1;
1288 if (istcp) {
1289 replysize = 65535;
1292 if (q->edns0len > 512)
1293 replysize = q->edns0len;
1295 /* st */
1297 odh = (struct dns_header *)&reply[0];
1298 outlen = sizeof(struct dns_header);
1300 if (len > replysize) {
1301 return (retlen);
1304 /* copy question to reply */
1305 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1306 /* blank query */
1307 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1309 outlen += (q->hdr->namelen + 4);
1311 SET_DNS_REPLY(odh);
1312 if (sreply->sr == NULL)
1313 SET_DNS_AUTHORITATIVE(odh);
1314 else
1315 SET_DNS_RECURSION_AVAIL(odh);
1317 NTOHS(odh->query);
1319 odh->question = htons(1);
1320 odh->answer = htons(1);
1321 odh->nsrr = 0;
1322 odh->additional = 0;
1324 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1325 q->hdr->namelen + 4);
1327 answer->name[0] = 0xc0;
1328 answer->name[1] = 0x0c;
1329 answer->type = q->hdr->qtype;
1330 answer->class = q->hdr->qclass;
1331 if (sreply->sr != NULL)
1332 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1333 else
1334 answer->ttl = htonl(sd->ttl);
1336 outlen += 12; /* up to rdata length */
1338 p = (char *)&answer->rdata;
1341 label = sd->soa.nsserver;
1342 labellen = sd->soa.nsserver_len;
1344 plabel = label;
1346 /* copy label to reply */
1347 for (i = outlen; i < replysize; i++) {
1348 if (i - outlen == labellen)
1349 break;
1351 reply[i] = *plabel++;
1354 if (i >= replysize) {
1355 return (retlen);
1358 outlen = i;
1360 /* compress the label if possible */
1361 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
1362 outlen = tmplen;
1365 label = sd->soa.responsible_person;
1366 labellen = sd->soa.rp_len;
1367 plabel = label;
1369 for (i = outlen; i < replysize; i++) {
1370 if (i - outlen == labellen)
1371 break;
1373 reply[i] = *plabel++;
1376 if (i >= replysize) {
1377 return (retlen);
1380 outlen = i;
1382 /* 2 compress the label if possible */
1384 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
1385 outlen = tmplen;
1389 /* XXX */
1390 if ((outlen + sizeof(sd->soa.serial)) > replysize) {
1391 /* XXX server error reply? */
1392 return (retlen);
1394 soa_val = (u_int32_t *)&reply[outlen];
1395 *soa_val = htonl(sd->soa.serial);
1396 outlen += sizeof(sd->soa.serial); /* XXX */
1398 /* XXX */
1399 if ((outlen + sizeof(sd->soa.refresh)) > replysize) {
1400 return (retlen);
1402 soa_val = (u_int32_t *)&reply[outlen];
1403 *soa_val = htonl(sd->soa.refresh);
1404 outlen += sizeof(sd->soa.refresh); /* XXX */
1406 if ((outlen + sizeof(sd->soa.retry)) > replysize) {
1407 return (retlen);
1409 soa_val = (u_int32_t *)&reply[outlen];
1410 *soa_val = htonl(sd->soa.retry);
1411 outlen += sizeof(sd->soa.retry); /* XXX */
1413 if ((outlen + sizeof(sd->soa.expire)) > replysize) {
1414 return (retlen);
1416 soa_val = (u_int32_t *)&reply[outlen];
1417 *soa_val = htonl(sd->soa.expire);
1418 outlen += sizeof(sd->soa.expire);
1420 if ((outlen + sizeof(sd->soa.minttl)) > replysize) {
1421 return (retlen);
1423 soa_val = (u_int32_t *)&reply[outlen];
1424 *soa_val = htonl(sd->soa.minttl);
1425 outlen += sizeof(sd->soa.minttl);
1427 answer->rdlength = htons(&reply[outlen] - &answer->rdata);
1429 if (q->edns0len) {
1430 /* tag on edns0 opt record */
1431 NTOHS(odh->additional);
1432 odh->additional++;
1433 HTONS(odh->additional);
1435 outlen = additional_opt(q, reply, replysize, outlen);
1438 if (sreply->sr != NULL) {
1439 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1440 } else {
1441 if (istcp) {
1442 char *tmpbuf;
1443 u_int16_t *plen;
1445 tmpbuf = malloc(outlen + 2);
1446 if (tmpbuf == NULL) {
1447 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1449 plen = (u_int16_t *)tmpbuf;
1450 *plen = htons(outlen);
1452 memcpy(&tmpbuf[2], reply, outlen);
1454 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1455 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1457 free(tmpbuf);
1458 } else {
1459 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1460 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1465 return (retlen);
1469 * REPLY_SPF() - replies a DNS question (*q) on socket (so)
1470 * based on reply_txt...
1474 int
1475 reply_spf(struct sreply *sreply)
1477 char *reply = sreply->replybuf;
1478 struct dns_header *odh;
1479 u_int16_t outlen;
1480 char *p;
1482 struct answer {
1483 char name[2];
1484 u_int16_t type;
1485 u_int16_t class;
1486 u_int32_t ttl;
1487 u_int16_t rdlength; /* 12 */
1488 char rdata;
1489 } __attribute__((packed));
1491 struct answer *answer;
1493 int so = sreply->so;
1494 char *buf = sreply->buf;
1495 int len = sreply->len;
1496 struct question *q = sreply->q;
1497 struct sockaddr *sa = sreply->sa;
1498 int salen = sreply->salen;
1499 struct domain *sd = sreply->sd1;
1500 int istcp = sreply->istcp;
1501 int replysize = 512;
1502 int retlen = -1;
1504 if (istcp) {
1505 replysize = 65535;
1508 if (q->edns0len > 512)
1509 replysize = q->edns0len;
1511 /* st */
1513 odh = (struct dns_header *)&reply[0];
1514 outlen = sizeof(struct dns_header);
1516 if (len > replysize) {
1517 return (retlen);
1520 /* copy question to reply */
1521 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1522 /* blank query */
1523 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1525 outlen += (q->hdr->namelen + 4);
1527 SET_DNS_REPLY(odh);
1528 if (sreply->sr == NULL)
1529 SET_DNS_AUTHORITATIVE(odh);
1530 else
1531 SET_DNS_RECURSION_AVAIL(odh);
1533 HTONS(odh->query);
1535 odh->question = htons(1);
1536 odh->answer = htons(1);
1537 odh->nsrr = 0;
1538 odh->additional = 0;
1540 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1541 q->hdr->namelen + 4);
1543 answer->name[0] = 0xc0;
1544 answer->name[1] = 0x0c;
1545 answer->type = q->hdr->qtype;
1546 answer->class = q->hdr->qclass;
1547 if (sreply->sr != NULL)
1548 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1549 else
1550 answer->ttl = htonl(sd->ttl);
1552 outlen += 12; /* up to rdata length */
1554 p = (char *)&answer->rdata;
1556 *p = sd->spflen;
1557 memcpy((p + 1), sd->spf, sd->spflen);
1558 outlen += (sd->spflen + 1);
1560 answer->rdlength = htons(sd->spflen + 1);
1562 if (q->edns0len) {
1563 /* tag on edns0 opt record */
1564 NTOHS(odh->additional);
1565 odh->additional++;
1566 HTONS(odh->additional);
1568 outlen = additional_opt(q, reply, replysize, outlen);
1571 if (sreply->sr != NULL) {
1572 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1573 } else {
1574 if (istcp) {
1575 char *tmpbuf;
1576 u_int16_t *plen;
1578 tmpbuf = malloc(outlen + 2);
1579 if (tmpbuf == NULL) {
1580 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1582 plen = (u_int16_t *)tmpbuf;
1583 *plen = htons(outlen);
1585 memcpy(&tmpbuf[2], reply, outlen);
1587 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1588 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1590 free(tmpbuf);
1591 } else {
1592 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1593 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1598 return (retlen);
1602 * REPLY_TXT() - replies a DNS question (*q) on socket (so)
1607 int
1608 reply_txt(struct sreply *sreply)
1610 char *reply = sreply->replybuf;
1611 struct dns_header *odh;
1612 u_int16_t outlen;
1613 char *p;
1615 struct answer {
1616 char name[2];
1617 u_int16_t type;
1618 u_int16_t class;
1619 u_int32_t ttl;
1620 u_int16_t rdlength; /* 12 */
1621 char rdata;
1622 } __attribute__((packed));
1624 struct answer *answer;
1626 int so = sreply->so;
1627 char *buf = sreply->buf;
1628 int len = sreply->len;
1629 struct question *q = sreply->q;
1630 struct sockaddr *sa = sreply->sa;
1631 int salen = sreply->salen;
1632 struct domain *sd = sreply->sd1;
1633 int istcp = sreply->istcp;
1634 int replysize = 512;
1635 int retlen = -1;
1637 if (istcp) {
1638 replysize = 65535;
1641 if (q->edns0len > 512)
1642 replysize = q->edns0len;
1644 /* st */
1646 odh = (struct dns_header *)&reply[0];
1647 outlen = sizeof(struct dns_header);
1649 if (len > replysize) {
1650 return (retlen);
1653 /* copy question to reply */
1654 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1655 /* blank query */
1656 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1658 outlen += (q->hdr->namelen + 4);
1660 SET_DNS_REPLY(odh);
1661 if (sreply->sr == NULL)
1662 SET_DNS_AUTHORITATIVE(odh);
1663 else
1664 SET_DNS_RECURSION_AVAIL(odh);
1666 HTONS(odh->query);
1668 odh->question = htons(1);
1669 odh->answer = htons(1);
1670 odh->nsrr = 0;
1671 odh->additional = 0;
1673 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1674 q->hdr->namelen + 4);
1676 answer->name[0] = 0xc0;
1677 answer->name[1] = 0x0c;
1678 answer->type = q->hdr->qtype;
1679 answer->class = q->hdr->qclass;
1680 if (sreply->sr != NULL)
1681 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1682 else
1683 answer->ttl = htonl(sd->ttl);
1685 outlen += 12; /* up to rdata length */
1687 p = (char *)&answer->rdata;
1689 *p = sd->txtlen;
1690 memcpy((p + 1), sd->txt, sd->txtlen);
1691 outlen += (sd->txtlen + 1);
1693 answer->rdlength = htons(sd->txtlen + 1);
1695 if (q->edns0len) {
1696 /* tag on edns0 opt record */
1697 NTOHS(odh->additional);
1698 odh->additional++;
1699 HTONS(odh->additional);
1701 outlen = additional_opt(q, reply, replysize, outlen);
1704 if (sreply->sr != NULL) {
1705 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1706 } else {
1707 if (istcp) {
1708 char *tmpbuf;
1709 u_int16_t *plen;
1711 tmpbuf = malloc(outlen + 2);
1712 if (tmpbuf == NULL) {
1713 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1715 plen = (u_int16_t *)tmpbuf;
1716 *plen = htons(outlen);
1718 memcpy(&tmpbuf[2], reply, outlen);
1720 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1721 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1723 free(tmpbuf);
1724 } else {
1725 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1726 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1731 return (retlen);
1735 * REPLY_SSHFP() - replies a DNS question (*q) on socket (so)
1736 * (based on reply_srv)
1740 int
1741 reply_sshfp(struct sreply *sreply)
1743 char *reply = sreply->replybuf;
1744 struct dns_header *odh;
1745 int sshfp_count;
1746 u_int16_t *plen;
1747 u_int16_t outlen;
1749 struct answer {
1750 char name[2];
1751 u_int16_t type;
1752 u_int16_t class;
1753 u_int32_t ttl;
1754 u_int16_t rdlength; /* 12 */
1755 u_int8_t sshfp_alg;
1756 u_int8_t sshfp_type;
1757 char target;
1758 } __attribute__((packed));
1760 struct answer *answer;
1762 int so = sreply->so;
1763 char *buf = sreply->buf;
1764 int len = sreply->len;
1765 struct question *q = sreply->q;
1766 struct sockaddr *sa = sreply->sa;
1767 int salen = sreply->salen;
1768 struct domain *sd = sreply->sd1;
1769 int istcp = sreply->istcp;
1770 int typelen = 0;
1771 int replysize = 512;
1772 int retlen = -1;
1774 if (istcp) {
1775 replysize = 65535;
1778 if (q->edns0len > 512)
1779 replysize = q->edns0len;
1782 odh = (struct dns_header *)&reply[0];
1784 outlen = sizeof(struct dns_header);
1786 if (len > replysize) {
1787 return (retlen);
1790 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1791 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1793 outlen += (q->hdr->namelen + 4);
1795 SET_DNS_REPLY(odh);
1797 if (sreply->sr == NULL) {
1798 SET_DNS_AUTHORITATIVE(odh);
1799 } else
1800 SET_DNS_RECURSION_AVAIL(odh);
1802 HTONS(odh->query);
1804 odh->question = htons(1);
1805 odh->answer = htons(sd->sshfp_count);
1806 odh->nsrr = 0;
1807 odh->additional = 0;
1809 /* skip dns header, question name, qtype and qclass */
1810 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1811 q->hdr->namelen + 4);
1813 sshfp_count = 0;
1814 do {
1815 answer->name[0] = 0xc0;
1816 answer->name[1] = 0x0c;
1817 answer->type = q->hdr->qtype;
1818 answer->class = q->hdr->qclass;
1819 if (sreply->sr != NULL)
1820 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1821 else
1822 answer->ttl = htonl(sd->ttl);
1824 switch (sd->sshfp[sshfp_count].fptype) {
1825 case 1:
1826 typelen = DNS_SSHFP_SIZE_SHA1;
1827 break;
1828 case 2:
1829 typelen = DNS_SSHFP_SIZE_SHA256;
1830 break;
1831 default:
1832 dolog(LOG_ERR, "oops bad sshfp type? not returning a packet!\n");
1833 return (retlen);
1836 answer->rdlength = htons((2 * sizeof(u_int8_t)) + typelen);
1837 answer->sshfp_alg = sd->sshfp[sshfp_count].algorithm;
1838 answer->sshfp_type = sd->sshfp[sshfp_count].fptype;
1840 memcpy((char *)&answer->target, (char *)sd->sshfp[sshfp_count].fingerprint, sd->sshfp[sshfp_count].fplen);
1842 /* can we afford to write another header? if no truncate */
1843 if (sd->sshfp_count > 1 && (outlen + 12 + 2 + sd->sshfp[sshfp_count].fplen) > replysize) {
1844 NTOHS(odh->query);
1845 SET_DNS_TRUNCATION(odh);
1846 HTONS(odh->query);
1847 goto out;
1850 /* set new offset for answer */
1851 outlen += (12 + 2 + sd->sshfp[sshfp_count].fplen);
1852 answer = (struct answer *)&reply[outlen];
1853 } while (++sshfp_count < RECORD_COUNT && --sd->sshfp_count);
1855 if (q->edns0len) {
1856 /* tag on edns0 opt record */
1857 NTOHS(odh->additional);
1858 odh->additional++;
1859 HTONS(odh->additional);
1861 outlen = additional_opt(q, reply, replysize, outlen);
1864 out:
1865 if (sreply->sr != NULL) {
1866 retlen = reply_raw2(so, reply, outlen, sreply->sr);
1867 } else {
1868 if (istcp) {
1869 char *tmpbuf;
1871 tmpbuf = malloc(outlen + 2);
1872 if (tmpbuf == NULL) {
1873 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
1875 plen = (u_int16_t *)tmpbuf;
1876 *plen = htons(outlen);
1878 memcpy(&tmpbuf[2], reply, outlen);
1879 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
1880 dolog(LOG_INFO, "send: %s\n", strerror(errno));
1882 free(tmpbuf);
1883 } else {
1884 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
1885 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
1890 return (retlen);
1895 * REPLY_NAPTR() - replies a DNS question (*q) on socket (so)
1896 * (based on reply_srv)
1900 int
1901 reply_naptr(struct sreply *sreply, DB *db)
1903 char *reply = sreply->replybuf;
1904 struct dns_header *odh;
1905 struct domain *sd0;
1906 int naptr_count;
1907 u_int16_t *plen;
1908 char *name;
1909 u_int16_t outlen;
1910 u_int16_t namelen;
1911 int additional = 0;
1913 struct answer {
1914 char name[2];
1915 u_int16_t type;
1916 u_int16_t class;
1917 u_int32_t ttl;
1918 u_int16_t rdlength; /* 12 */
1919 u_int16_t naptr_order;
1920 u_int16_t naptr_preference;
1921 char rest;
1922 } __attribute__((packed));
1924 struct answer *answer;
1926 int so = sreply->so;
1927 char *buf = sreply->buf;
1928 int len = sreply->len;
1929 struct question *q = sreply->q;
1930 struct sockaddr *sa = sreply->sa;
1931 int salen = sreply->salen;
1932 struct domain *sd = sreply->sd1;
1933 int istcp = sreply->istcp;
1934 int wildcard = sreply->wildcard;
1935 int replysize = 512;
1936 int tmplen, savelen;
1937 char *p;
1938 int retlen = -1;
1940 if (istcp) {
1941 replysize = 65535;
1944 if (q->edns0len > 512)
1945 replysize = q->edns0len;
1947 odh = (struct dns_header *)&reply[0];
1949 outlen = sizeof(struct dns_header);
1951 if (len > replysize) {
1952 return (retlen);
1955 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
1956 memset((char *)&odh->query, 0, sizeof(u_int16_t));
1958 outlen += (q->hdr->namelen + 4);
1960 SET_DNS_REPLY(odh);
1962 if (sreply->sr == NULL) {
1963 SET_DNS_AUTHORITATIVE(odh);
1964 } else
1965 SET_DNS_RECURSION_AVAIL(odh);
1967 HTONS(odh->query);
1969 odh->question = htons(1);
1970 odh->answer = htons(sd->naptr_count);
1971 odh->nsrr = 0;
1972 odh->additional = 0;
1974 /* skip dns header, question name, qtype and qclass */
1975 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
1976 q->hdr->namelen + 4);
1978 naptr_count = 0;
1979 do {
1980 savelen = outlen;
1981 answer->name[0] = 0xc0;
1982 answer->name[1] = 0x0c;
1983 answer->type = q->hdr->qtype;
1984 answer->class = q->hdr->qclass;
1985 if (sreply->sr != NULL)
1986 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
1987 else
1988 answer->ttl = htonl(sd->ttl);
1990 answer->naptr_order = htons(sd->naptr[naptr_count].order);
1991 answer->naptr_preference = htons(sd->naptr[naptr_count].preference);
1993 p = (char *)&answer->rest;
1995 *p = sd->naptr[naptr_count].flagslen;
1996 memcpy((p + 1), sd->naptr[naptr_count].flags, sd->naptr[naptr_count].flagslen);
1997 p += (sd->naptr[naptr_count].flagslen + 1);
1998 outlen += (1 + sd->naptr[naptr_count].flagslen);
2000 /* services */
2001 *p = sd->naptr[naptr_count].serviceslen;
2002 memcpy((p + 1), sd->naptr[naptr_count].services, sd->naptr[naptr_count].serviceslen);
2003 p += (sd->naptr[naptr_count].serviceslen + 1);
2004 outlen += (1 + sd->naptr[naptr_count].serviceslen);
2006 /* regexp */
2007 *p = sd->naptr[naptr_count].regexplen;
2008 memcpy((p + 1), sd->naptr[naptr_count].regexp, sd->naptr[naptr_count].regexplen);
2009 p += (sd->naptr[naptr_count].regexplen + 1);
2010 outlen += (1 + sd->naptr[naptr_count].regexplen);
2012 /* replacement */
2014 memcpy((char *)p, (char *)sd->naptr[naptr_count].replacement, sd->naptr[naptr_count].replacementlen);
2016 name = sd->naptr[naptr_count].replacement;
2017 namelen = sd->naptr[naptr_count].replacementlen;
2019 outlen += (12 + 4 + sd->naptr[naptr_count].replacementlen);
2021 /* compress the label if possible */
2022 if ((tmplen = compress_label((u_char*)reply, outlen, namelen)) > 0) {
2023 outlen = tmplen;
2026 answer->rdlength = htons(outlen - (savelen + 12));
2029 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_A), wildcard);
2030 if (sd0 != NULL) {
2031 cn1 = malloc(sizeof(struct collects));
2032 if (cn1 != NULL) {
2033 cn1->name = malloc(namelen);
2034 if (cn1->name != NULL) {
2035 memcpy(cn1->name, name, namelen);
2036 cn1->namelen = namelen;
2037 cn1->sd = sd0;
2038 cn1->type = DNS_TYPE_A;
2040 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
2044 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_AAAA), wildcard);
2045 if (sd0 != NULL) {
2046 cn1 = malloc(sizeof(struct collects));
2047 if (cn1 != NULL) {
2048 cn1->name = malloc(namelen);
2049 if (cn1->name != NULL) {
2050 memcpy(cn1->name, name, namelen);
2051 cn1->namelen = namelen;
2052 cn1->sd = sd0;
2053 cn1->type = DNS_TYPE_AAAA;
2055 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
2061 /* can we afford to write another header? if no truncate */
2062 if (sd->naptr_count > naptr_count && (outlen + 12 + 4 + sd->naptr[naptr_count + 1].replacementlen + sd->naptr[naptr_count + 1].flagslen + 1 + sd->naptr[naptr_count + 1].serviceslen + 1 + sd->naptr[naptr_count + 1].regexplen + 1) > replysize) {
2063 NTOHS(odh->query);
2064 SET_DNS_TRUNCATION(odh);
2065 HTONS(odh->query);
2066 goto out;
2069 /* set new offset for answer */
2070 answer = (struct answer *)&reply[outlen];
2071 } while (++naptr_count < RECORD_COUNT && --sd->naptr_count);
2073 /* write additional */
2075 SLIST_FOREACH(cnp, &collectshead, collect_entry) {
2076 int addcount;
2077 int tmplen;
2079 switch (cnp->type) {
2080 case DNS_TYPE_A:
2081 tmplen = additional_a(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
2082 additional += addcount;
2083 break;
2084 case DNS_TYPE_AAAA:
2085 tmplen = additional_aaaa(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
2086 additional += addcount;
2087 break;
2090 if (tmplen > 0) {
2091 outlen = tmplen;
2095 odh->additional = htons(additional);
2097 while (!SLIST_EMPTY(&collectshead)) {
2098 cn1 = SLIST_FIRST(&collectshead);
2099 SLIST_REMOVE_HEAD(&collectshead, collect_entry);
2100 free(cn1->name);
2101 free(cn1->sd);
2102 free(cn1);
2105 if (q->edns0len) {
2106 /* tag on edns0 opt record */
2107 NTOHS(odh->additional);
2108 odh->additional++;
2109 HTONS(odh->additional);
2111 outlen = additional_opt(q, reply, replysize, outlen);
2114 out:
2115 if (sreply->sr != NULL) {
2116 retlen = reply_raw2(so, reply, outlen, sreply->sr);
2117 } else {
2118 if (istcp) {
2119 char *tmpbuf;
2121 tmpbuf = malloc(outlen + 2);
2122 if (tmpbuf == NULL) {
2123 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2125 plen = (u_int16_t *)tmpbuf;
2126 *plen = htons(outlen);
2128 memcpy(&tmpbuf[2], reply, outlen);
2129 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2130 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2132 free(tmpbuf);
2133 } else {
2134 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
2135 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2140 return (retlen);
2145 * REPLY_SRV() - replies a DNS question (*q) on socket (so)
2146 * (based on reply_mx)
2150 int
2151 reply_srv(struct sreply *sreply, DB *db)
2153 char *reply = sreply->replybuf;
2154 struct dns_header *odh;
2155 struct domain *sd0;
2156 int srv_count;
2157 u_int16_t *plen;
2158 char *name;
2159 u_int16_t outlen;
2160 u_int16_t namelen;
2161 int additional = 0;
2163 struct answer {
2164 char name[2];
2165 u_int16_t type;
2166 u_int16_t class;
2167 u_int32_t ttl;
2168 u_int16_t rdlength; /* 12 */
2169 u_int16_t srv_priority;
2170 u_int16_t srv_weight;
2171 u_int16_t srv_port;
2172 char target;
2173 } __attribute__((packed));
2175 struct answer *answer;
2177 int so = sreply->so;
2178 char *buf = sreply->buf;
2179 int len = sreply->len;
2180 struct question *q = sreply->q;
2181 struct sockaddr *sa = sreply->sa;
2182 int salen = sreply->salen;
2183 struct domain *sd = sreply->sd1;
2184 int istcp = sreply->istcp;
2185 int wildcard = sreply->wildcard;
2186 int replysize = 512;
2187 int retlen = -1;
2189 if (istcp) {
2190 replysize = 65535;
2193 if (q->edns0len > 512)
2194 replysize = q->edns0len;
2196 odh = (struct dns_header *)&reply[0];
2198 outlen = sizeof(struct dns_header);
2200 if (len > replysize) {
2201 return (retlen);
2204 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
2205 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2207 outlen += (q->hdr->namelen + 4);
2209 SET_DNS_REPLY(odh);
2211 if (sreply->sr == NULL) {
2212 SET_DNS_AUTHORITATIVE(odh);
2213 } else
2214 SET_DNS_RECURSION_AVAIL(odh);
2216 HTONS(odh->query);
2218 odh->question = htons(1);
2219 odh->answer = htons(sd->srv_count);
2220 odh->nsrr = 0;
2221 odh->additional = 0;
2223 /* skip dns header, question name, qtype and qclass */
2224 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
2225 q->hdr->namelen + 4);
2227 srv_count = 0;
2228 do {
2229 answer->name[0] = 0xc0;
2230 answer->name[1] = 0x0c;
2231 answer->type = q->hdr->qtype;
2232 answer->class = q->hdr->qclass;
2233 if (sreply->sr != NULL)
2234 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
2235 else
2236 answer->ttl = htonl(sd->ttl);
2238 answer->rdlength = htons((3 * sizeof(u_int16_t)) + sd->srv[srv_count].targetlen);
2240 answer->srv_priority = htons(sd->srv[srv_count].priority);
2241 answer->srv_weight = htons(sd->srv[srv_count].weight);
2242 answer->srv_port = htons(sd->srv[srv_count].port);
2244 memcpy((char *)&answer->target, (char *)sd->srv[srv_count].target, sd->srv[srv_count].targetlen);
2246 name = sd->srv[srv_count].target;
2247 namelen = sd->srv[srv_count].targetlen;
2249 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_A), wildcard);
2250 if (sd0 != NULL) {
2251 cn1 = malloc(sizeof(struct collects));
2252 if (cn1 != NULL) {
2253 cn1->name = malloc(namelen);
2254 if (cn1->name != NULL) {
2255 memcpy(cn1->name, name, namelen);
2256 cn1->namelen = namelen;
2257 cn1->sd = sd0;
2258 cn1->type = DNS_TYPE_A;
2260 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
2264 sd0 = Lookup_zone(db, name, namelen, htons(DNS_TYPE_AAAA), wildcard);
2265 if (sd0 != NULL) {
2266 cn1 = malloc(sizeof(struct collects));
2267 if (cn1 != NULL) {
2268 cn1->name = malloc(namelen);
2269 if (cn1->name != NULL) {
2270 memcpy(cn1->name, name, namelen);
2271 cn1->namelen = namelen;
2272 cn1->sd = sd0;
2273 cn1->type = DNS_TYPE_AAAA;
2275 SLIST_INSERT_HEAD(&collectshead, cn1, collect_entry);
2280 outlen += (12 + 6 + sd->srv[srv_count].targetlen);
2282 /* can we afford to write another header? if no truncate */
2283 if (sd->srv_count > 1 && (outlen + 12 + 6 + sd->srv[srv_count].targetlen) > replysize) {
2284 NTOHS(odh->query);
2285 SET_DNS_TRUNCATION(odh);
2286 HTONS(odh->query);
2287 goto out;
2290 /* set new offset for answer */
2291 answer = (struct answer *)&reply[outlen];
2292 } while (++srv_count < RECORD_COUNT && --sd->srv_count);
2294 /* write additional */
2296 SLIST_FOREACH(cnp, &collectshead, collect_entry) {
2297 int addcount;
2298 int tmplen;
2300 switch (cnp->type) {
2301 case DNS_TYPE_A:
2302 tmplen = additional_a(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
2303 additional += addcount;
2304 break;
2305 case DNS_TYPE_AAAA:
2306 tmplen = additional_aaaa(cnp->name, cnp->namelen, cnp->sd, reply, replysize, outlen, &addcount);
2307 additional += addcount;
2308 break;
2311 if (tmplen > 0) {
2312 outlen = tmplen;
2316 odh->additional = htons(additional);
2318 while (!SLIST_EMPTY(&collectshead)) {
2319 cn1 = SLIST_FIRST(&collectshead);
2320 SLIST_REMOVE_HEAD(&collectshead, collect_entry);
2321 free(cn1->name);
2322 free(cn1->sd);
2323 free(cn1);
2326 if (q->edns0len) {
2327 /* tag on edns0 opt record */
2328 NTOHS(odh->additional);
2329 odh->additional++;
2330 HTONS(odh->additional);
2332 outlen = additional_opt(q, reply, replysize, outlen);
2335 out:
2336 if (sreply->sr != NULL) {
2337 retlen = reply_raw2(so, reply, outlen, sreply->sr);
2338 } else {
2339 if (istcp) {
2340 char *tmpbuf;
2342 tmpbuf = malloc(outlen + 2);
2343 if (tmpbuf == NULL) {
2344 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2346 plen = (u_int16_t *)tmpbuf;
2347 *plen = htons(outlen);
2349 memcpy(&tmpbuf[2], reply, outlen);
2350 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2351 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2353 free(tmpbuf);
2354 } else {
2355 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
2356 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2361 return (retlen);
2366 * REPLY_NOTIMPL - reply "Not Implemented"
2371 int
2372 reply_notimpl(struct sreply *sreply)
2374 char *reply = sreply->replybuf;
2375 struct dns_header *odh;
2376 u_int16_t outlen;
2378 int so = sreply->so;
2379 char *buf = sreply->buf;
2380 int len = sreply->len;
2381 struct sockaddr *sa = sreply->sa;
2382 int salen = sreply->salen;
2383 int istcp = sreply->istcp;
2384 int replysize = 512;
2385 int retlen = -1;
2387 if (istcp) {
2388 replysize = 65535;
2391 #if 0
2392 struct domain *sd = sreply->sd1;
2393 struct question *q = sreply->q;
2394 #endif
2396 odh = (struct dns_header *)&reply[0];
2398 outlen = sizeof(struct dns_header);
2400 if (len > replysize) {
2401 return (retlen);
2404 memcpy(reply, buf, len);
2406 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2408 SET_DNS_REPLY(odh);
2409 SET_DNS_RCODE_NOTIMPL(odh);
2411 HTONS(odh->query);
2414 if (istcp) {
2415 char *tmpbuf;
2416 u_int16_t *plen;
2418 tmpbuf = malloc(outlen + 2);
2419 if (tmpbuf == NULL) {
2420 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2422 plen = (u_int16_t *)tmpbuf;
2423 *plen = htons(outlen);
2425 memcpy(&tmpbuf[2], reply, outlen);
2427 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2428 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2430 free(tmpbuf);
2431 } else {
2432 if ((retlen = sendto(so, reply, len, 0, sa, salen)) < 0) {
2433 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2437 return (retlen);
2441 * REPLY_NXDOMAIN() - replies a DNS question (*q) on socket (so)
2445 int
2446 reply_nxdomain(struct sreply *sreply)
2448 char *reply = sreply->replybuf;
2449 struct dns_header *odh;
2450 u_int16_t outlen;
2451 char *p;
2452 u_int32_t *soa_val;
2453 int i, tmplen;
2454 int labellen;
2455 char *label, *plabel;
2457 struct answer {
2458 char name[2];
2459 u_int16_t type;
2460 u_int16_t class;
2461 u_int32_t ttl;
2462 u_int16_t rdlength; /* 12 */
2463 char rdata;
2464 } __attribute__((packed));
2466 struct soa {
2467 char *nsserver;
2468 char *responsible_person;
2469 u_int32_t serial;
2470 u_int32_t refresh;
2471 u_int32_t retry;
2472 u_int32_t expire;
2473 u_int32_t minttl;
2477 struct answer *answer;
2479 int so = sreply->so;
2480 char *buf = sreply->buf;
2481 int len = sreply->len;
2482 struct question *q = sreply->q;
2483 struct sockaddr *sa = sreply->sa;
2484 int salen = sreply->salen;
2485 struct domain *sd = sreply->sd1;
2486 int istcp = sreply->istcp;
2487 int replysize = 512;
2488 int retlen = -1;
2490 if (istcp) {
2491 replysize = 65535;
2494 odh = (struct dns_header *)&reply[0];
2495 outlen = sizeof(struct dns_header);
2497 if (len > replysize) {
2498 return (retlen);
2503 * no SOA, use the old code
2506 if ((sd->flags & DOMAIN_HAVE_SOA) != DOMAIN_HAVE_SOA) {
2508 memcpy(reply, buf, len);
2509 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2511 SET_DNS_REPLY(odh);
2512 #if 1
2513 if (sreply->sr != NULL) {
2514 SET_DNS_RECURSION_AVAIL(odh);
2516 #endif
2517 SET_DNS_RCODE_NAMEERR(odh);
2521 HTONS(odh->query);
2522 if (sreply->sr != NULL) {
2523 retlen = reply_raw2(so, reply, len, sreply->sr);
2524 } else {
2525 if (istcp) {
2526 char *tmpbuf;
2527 u_int16_t *plen;
2529 tmpbuf = malloc(len + 2);
2530 if (tmpbuf == NULL) {
2531 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2533 plen = (u_int16_t *)tmpbuf;
2534 *plen = htons(len);
2536 memcpy(&tmpbuf[2], reply, len);
2538 if ((retlen = send(so, tmpbuf, len + 2, 0)) < 0) {
2539 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2541 free(tmpbuf);
2542 } else {
2543 if ((retlen = sendto(so, reply, len, 0, sa, salen)) < 0) {
2544 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2549 return (retlen);
2552 /* copy question to reply */
2553 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
2554 /* blank query */
2555 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2557 outlen += (q->hdr->namelen + 4);
2559 SET_DNS_REPLY(odh);
2560 if (sreply->sr != NULL)
2561 SET_DNS_RECURSION_AVAIL(odh);
2562 else
2563 SET_DNS_AUTHORITATIVE(odh);
2565 SET_DNS_RCODE_NAMEERR(odh);
2567 NTOHS(odh->query);
2569 odh->question = htons(1);
2570 odh->answer = 0;
2571 odh->nsrr = htons(1);
2572 odh->additional = 0;
2574 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
2575 q->hdr->namelen + 4);
2577 answer->name[0] = 0xc0;
2578 answer->name[1] = 0x0c;
2579 answer->type = htons(DNS_TYPE_SOA);
2580 answer->class = q->hdr->qclass;
2581 if (sreply->sr != NULL)
2582 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
2583 else
2584 answer->ttl = htonl(sd->ttl);
2586 outlen += 12; /* up to rdata length */
2588 p = (char *)&answer->rdata;
2590 #if 0
2591 label = dns_label((char *)mysoa.nsserver, &labellen);
2592 if (label == NULL)
2593 return (retlen);
2594 #endif
2596 label = &sd->soa.nsserver[0];
2597 labellen = sd->soa.nsserver_len;
2599 plabel = label;
2601 /* copy label to reply */
2602 for (i = outlen; i < replysize; i++) {
2603 if (i - outlen == labellen)
2604 break;
2606 reply[i] = *plabel++;
2609 if (i >= replysize) {
2610 return (retlen);
2613 outlen = i;
2615 /* compress the label if possible */
2616 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
2617 outlen = tmplen;
2620 label = sd->soa.responsible_person;
2621 labellen = sd->soa.rp_len;
2622 plabel = label;
2624 for (i = outlen; i < replysize; i++) {
2625 if (i - outlen == labellen)
2626 break;
2628 reply[i] = *plabel++;
2631 if (i >= replysize) {
2632 return (retlen);
2635 outlen = i;
2637 /* 2 compress the label if possible */
2639 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
2640 outlen = tmplen;
2644 /* XXX */
2645 if ((outlen + sizeof(sd->soa.serial)) > replysize) {
2646 /* XXX server error reply? */
2647 return (retlen);
2649 soa_val = (u_int32_t *)&reply[outlen];
2650 *soa_val = htonl(sd->soa.serial);
2651 outlen += sizeof(sd->soa.serial);
2653 if ((outlen + sizeof(sd->soa.refresh)) > replysize) {
2654 return (retlen);
2656 soa_val = (u_int32_t *)&reply[outlen];
2657 *soa_val = htonl(sd->soa.refresh);
2658 outlen += sizeof(sd->soa.refresh);
2660 if ((outlen + sizeof(sd->soa.retry)) > replysize) {
2661 return (retlen);
2663 soa_val = (u_int32_t *)&reply[outlen];
2664 *soa_val = htonl(sd->soa.retry);
2665 outlen += sizeof(sd->soa.retry);
2667 if ((outlen + sizeof(sd->soa.expire)) > replysize) {
2668 return (retlen);
2670 soa_val = (u_int32_t *)&reply[outlen];
2671 *soa_val = htonl(sd->soa.expire);
2672 outlen += sizeof(sd->soa.expire);
2674 if ((outlen + sizeof(sd->soa.minttl)) > replysize) {
2675 return (retlen);
2677 soa_val = (u_int32_t *)&reply[outlen];
2678 *soa_val = htonl(sd->soa.minttl);
2679 outlen += sizeof(sd->soa.minttl);
2681 answer->rdlength = htons(&reply[outlen] - &answer->rdata);
2683 if (sreply->sr != NULL) {
2684 retlen = reply_raw2(so, reply, outlen, sreply->sr);
2685 } else {
2687 if (istcp) {
2688 char *tmpbuf;
2689 u_int16_t *plen;
2691 tmpbuf = malloc(outlen + 2);
2692 if (tmpbuf == NULL) {
2693 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2695 plen = (u_int16_t *)tmpbuf;
2696 *plen = htons(outlen);
2698 memcpy(&tmpbuf[2], reply, outlen);
2700 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2701 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2703 free(tmpbuf);
2704 } else {
2705 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
2706 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2709 } /* sreply->sr.. */
2711 return (retlen);
2715 * REPLY_REFUSED() - replies a DNS question (*q) on socket (so)
2719 int
2720 reply_refused(struct sreply *sreply)
2722 char *reply = sreply->replybuf;
2723 struct dns_header *odh;
2724 u_int16_t outlen;
2726 int so = sreply->so;
2727 int len = sreply->len;
2728 char *buf = sreply->buf;
2729 struct sockaddr *sa = sreply->sa;
2730 int salen = sreply->salen;
2731 int istcp = sreply->istcp;
2732 int replysize = 512;
2733 int retlen = -1;
2735 if (istcp) {
2736 replysize = 65535;
2739 memset(reply, 0, replysize);
2741 odh = (struct dns_header *)&reply[0];
2743 outlen = sizeof(struct dns_header);
2745 if (len > replysize) {
2746 return (retlen);
2749 memcpy((char *)&odh->id, buf, sizeof(u_int16_t));
2750 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2752 SET_DNS_REPLY(odh);
2753 SET_DNS_RCODE_REFUSED(odh);
2755 HTONS(odh->query);
2757 if (istcp) {
2758 char *tmpbuf;
2759 u_int16_t *plen;
2761 tmpbuf = malloc(outlen + 2);
2762 if (tmpbuf == NULL) {
2763 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2765 plen = (u_int16_t *)tmpbuf;
2766 *plen = htons(outlen);
2768 memcpy(&tmpbuf[2], reply, outlen);
2770 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2771 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2773 free(tmpbuf);
2774 } else {
2775 if ((retlen = sendto(so, reply, sizeof(struct dns_header), 0, sa, salen)) < 0) {
2776 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2780 return (retlen);
2784 * REPLY_FMTERROR() - replies a DNS question (*q) on socket (so)
2788 int
2789 reply_fmterror(struct sreply *sreply)
2791 char *reply = sreply->replybuf;
2792 struct dns_header *odh;
2793 u_int16_t outlen;
2795 int so = sreply->so;
2796 int len = sreply->len;
2797 char *buf = sreply->buf;
2798 struct sockaddr *sa = sreply->sa;
2799 int salen = sreply->salen;
2800 int istcp = sreply->istcp;
2801 int replysize = 512;
2802 int retlen = -1;
2804 if (istcp) {
2805 replysize = 65535;
2808 memset(reply, 0, replysize);
2810 odh = (struct dns_header *)&reply[0];
2812 outlen = sizeof(struct dns_header);
2814 if (len > replysize) {
2815 return (retlen);
2818 memcpy((char *)&odh->id, buf, sizeof(u_int16_t));
2819 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2821 SET_DNS_REPLY(odh);
2822 SET_DNS_RCODE_FORMATERR(odh);
2824 HTONS(odh->query);
2826 if (istcp) {
2827 char *tmpbuf;
2828 u_int16_t *plen;
2830 tmpbuf = malloc(outlen + 2);
2831 if (tmpbuf == NULL) {
2832 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2834 plen = (u_int16_t *)tmpbuf;
2835 *plen = htons(outlen);
2837 memcpy(&tmpbuf[2], reply, outlen);
2839 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
2840 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2842 free(tmpbuf);
2843 } else {
2844 if ((retlen = sendto(so, reply, sizeof(struct dns_header), 0, sa, salen)) < 0) {
2845 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2849 return (retlen);
2853 * REPLY_NOERROR() - replies a DNS question (*q) on socket (so)
2854 * based on reply_nxdomain
2858 int
2859 reply_noerror(struct sreply *sreply)
2861 char *reply = sreply->replybuf;
2862 struct dns_header *odh;
2863 u_int16_t outlen;
2864 char *p;
2865 u_int32_t *soa_val;
2866 int i, tmplen;
2867 int labellen;
2868 char *label, *plabel;
2870 struct answer {
2871 char name[2];
2872 u_int16_t type;
2873 u_int16_t class;
2874 u_int32_t ttl;
2875 u_int16_t rdlength; /* 12 */
2876 char rdata;
2877 } __attribute__((packed));
2879 struct soa {
2880 char *nsserver;
2881 char *responsible_person;
2882 u_int32_t serial;
2883 u_int32_t refresh;
2884 u_int32_t retry;
2885 u_int32_t expire;
2886 u_int32_t minttl;
2890 struct answer *answer;
2892 int so = sreply->so;
2893 char *buf = sreply->buf;
2894 int len = sreply->len;
2895 struct question *q = sreply->q;
2896 struct sockaddr *sa = sreply->sa;
2897 int salen = sreply->salen;
2898 struct domain *sd = sreply->sd1;
2899 int istcp = sreply->istcp;
2900 int replysize = 512;
2901 int retlen = -1;
2903 if (istcp) {
2904 replysize = 65535;
2907 if (q->edns0len > 512)
2908 replysize = q->edns0len;
2910 odh = (struct dns_header *)&reply[0];
2911 outlen = sizeof(struct dns_header);
2913 if (len > replysize) {
2914 return (retlen);
2919 * no SOA, use the old code
2922 if ((sd->flags & DOMAIN_HAVE_SOA) != DOMAIN_HAVE_SOA) {
2924 memcpy(reply, buf, len);
2925 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2927 SET_DNS_REPLY(odh);
2928 #if 0
2929 SET_DNS_RCODE_NAMEERR(odh);
2930 #endif
2932 HTONS(odh->query);
2934 if (istcp) {
2935 char *tmpbuf;
2936 u_int16_t *plen;
2938 tmpbuf = malloc(len + 2);
2939 if (tmpbuf == NULL) {
2940 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
2942 plen = (u_int16_t *)tmpbuf;
2943 *plen = htons(len);
2945 memcpy(&tmpbuf[2], reply, len);
2947 if ((retlen = send(so, tmpbuf, len + 2, 0)) < 0) {
2948 dolog(LOG_INFO, "send: %s\n", strerror(errno));
2950 free(tmpbuf);
2951 } else {
2952 if ((retlen = sendto(so, reply, len, 0, sa, salen)) < 0) {
2953 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
2957 return (retlen);
2960 /* copy question to reply */
2961 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
2962 /* blank query */
2963 memset((char *)&odh->query, 0, sizeof(u_int16_t));
2965 outlen += (q->hdr->namelen + 4);
2967 SET_DNS_REPLY(odh);
2969 if (sreply->sr == NULL)
2970 SET_DNS_AUTHORITATIVE(odh);
2971 else
2972 SET_DNS_RECURSION_AVAIL(odh);
2974 NTOHS(odh->query);
2976 odh->question = htons(1);
2977 odh->answer = 0;
2978 odh->nsrr = htons(1);
2979 odh->additional = 0;
2981 answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
2982 q->hdr->namelen + 4);
2984 answer->name[0] = 0xc0;
2985 answer->name[1] = 0x0c;
2986 answer->type = htons(DNS_TYPE_SOA);
2987 answer->class = q->hdr->qclass;
2988 if (sreply->sr != NULL)
2989 answer->ttl = htonl(sd->ttl - (time(NULL) - sd->created));
2990 else
2991 answer->ttl = htonl(sd->ttl);
2993 outlen += 12; /* up to rdata length */
2995 p = (char *)&answer->rdata;
2997 label = sd->soa.nsserver;
2998 labellen = sd->soa.nsserver_len;
3000 plabel = label;
3002 /* copy label to reply */
3003 for (i = outlen; i < replysize; i++) {
3004 if (i - outlen == labellen)
3005 break;
3007 reply[i] = *plabel++;
3010 if (i >= replysize) {
3011 return (retlen);
3014 outlen = i;
3016 /* compress the label if possible */
3017 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
3018 outlen = tmplen;
3021 label = &sd->soa.responsible_person[0];
3022 labellen = sd->soa.rp_len;
3023 plabel = label;
3025 for (i = outlen; i < replysize; i++) {
3026 if (i - outlen == labellen)
3027 break;
3029 reply[i] = *plabel++;
3032 if (i >= replysize) {
3033 return (retlen);
3036 outlen = i;
3038 /* 2 compress the label if possible */
3040 if ((tmplen = compress_label((u_char*)reply, outlen, labellen)) > 0) {
3041 outlen = tmplen;
3045 /* XXX */
3046 if ((outlen + sizeof(sd->soa.serial)) > replysize) {
3047 /* XXX server error reply? */
3048 return (retlen);
3050 soa_val = (u_int32_t *)&reply[outlen];
3051 *soa_val = htonl(sd->soa.serial);
3052 outlen += sizeof(sd->soa.serial);
3054 if ((outlen + sizeof(sd->soa.refresh)) > replysize) {
3055 return (retlen);
3057 soa_val = (u_int32_t *)&reply[outlen];
3058 *soa_val = htonl(sd->soa.refresh);
3059 outlen += sizeof(sd->soa.refresh);
3061 if ((outlen + sizeof(sd->soa.retry)) > replysize) {
3062 return (retlen);
3064 soa_val = (u_int32_t *)&reply[outlen];
3065 *soa_val = htonl(sd->soa.retry);
3066 outlen += sizeof(sd->soa.retry);
3068 if ((outlen + sizeof(sd->soa.expire)) > replysize) {
3069 return (retlen);
3071 soa_val = (u_int32_t *)&reply[outlen];
3072 *soa_val = htonl(sd->soa.expire);
3073 outlen += sizeof(sd->soa.expire);
3075 if ((outlen + sizeof(sd->soa.minttl)) > replysize) {
3076 return (retlen);
3078 soa_val = (u_int32_t *)&reply[outlen];
3079 *soa_val = htonl(sd->soa.minttl);
3080 outlen += sizeof(sd->soa.minttl);
3082 answer->rdlength = htons(&reply[outlen] - &answer->rdata);
3084 if (q->edns0len) {
3085 /* tag on edns0 opt record */
3086 NTOHS(odh->additional);
3087 odh->additional++;
3088 HTONS(odh->additional);
3090 outlen = additional_opt(q, reply, replysize, outlen);
3093 if (sreply->sr != NULL) {
3094 retlen = reply_raw2(so, reply, outlen, sreply->sr);
3095 } else {
3096 if (istcp) {
3097 char *tmpbuf;
3098 u_int16_t *plen;
3100 tmpbuf = malloc(outlen + 2);
3101 if (tmpbuf == NULL) {
3102 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
3104 plen = (u_int16_t *)tmpbuf;
3105 *plen = htons(outlen);
3107 memcpy(&tmpbuf[2], reply, outlen);
3109 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
3110 dolog(LOG_INFO, "send: %s\n", strerror(errno));
3112 free(tmpbuf);
3113 } else {
3114 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
3115 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
3120 return (retlen);
3123 void
3124 update_db(DB *db, struct domain *sd)
3126 int ret;
3127 int i = 0;
3128 DBT key, data;
3131 do {
3132 if (++i == 32) {
3133 dolog(LOG_ERR, "could not update zone for 32 tries, giving up entire database, quit");
3134 slave_shutdown();
3135 exit(1);
3138 memset(&key, 0, sizeof(key));
3139 memset(&data, 0, sizeof(data));
3141 key.data = sd->zone;
3142 key.size = sd->zonelen;
3144 data.data = (char *)sd;
3145 data.size = sizeof(struct domain);
3147 ret = db->put(db, NULL, &key, &data, 0);
3148 } while (ret != 0);
3150 return;
3154 * Lookup_zone: wrapper for lookup_zone() et al.
3157 struct domain *
3158 Lookup_zone(DB *db, char *name, u_int16_t namelen, u_int16_t type, int wildcard)
3160 struct domain *sd;
3161 struct question *fakequestion;
3162 char fakereplystring[DNS_MAXNAME + 1];
3163 int mytype;
3164 int lzerrno;
3166 fakequestion = build_fake_question(name, namelen, type);
3167 if (fakequestion == NULL) {
3168 dolog(LOG_INFO, "fakequestion(2) failed\n");
3169 return (NULL);
3172 sd = calloc(sizeof(struct domain), 1);
3173 if (sd == NULL) {
3174 dolog(LOG_INFO, "calloc: %s\n", strerror(errno));
3175 free_question(fakequestion);
3176 return (NULL);
3179 mytype = lookup_zone(db, fakequestion, sd, &lzerrno, (char *)&fakereplystring, wildcard);
3181 if (mytype < 0) {
3182 free(sd);
3183 free_question(fakequestion);
3184 return (NULL);
3187 free_question(fakequestion);
3189 return (sd);
3192 void
3193 collects_init(void)
3195 SLIST_INIT(&collectshead);
3198 int
3199 reply_raw2(int so, char *reply, int outlen, struct recurses *sr)
3201 char buf[2048];
3202 #ifdef __linux__
3203 struct iphdr *ip;
3204 #else
3205 struct ip *ip;
3206 #endif
3207 struct udphdr *udp;
3208 int udplen = outlen + sizeof(struct udphdr);
3209 struct sockaddr_in *sin_src, *sin_dst;
3210 int retlen = -1;
3212 if (sr->af == AF_INET6) {
3213 retlen = reply_raw6(so, reply, outlen, sr);
3214 return (retlen);
3217 #ifdef __linux__
3218 ip = (struct iphdr *)&buf[0];
3219 #else
3220 ip = (struct ip *)&buf[0];
3221 #endif
3222 udp = (struct udphdr *)&buf[sizeof(struct ip)];
3223 memcpy(&buf[sizeof(struct ip) + sizeof(struct udphdr)], reply, outlen);
3225 #ifdef __linux__
3226 ip->version = IPVERSION;
3227 ip->ihl = sizeof(struct iphdr) >> 2;
3229 ip->tos = 0;
3230 ip->tot_len = htons(udplen + sizeof(struct iphdr));
3231 ip->id = arc4random() & 0xffff;
3232 ip->frag_off = htons(IP_DF);
3233 ip->ttl = 64;
3234 ip->protocol = IPPROTO_UDP;
3235 ip->check = 0;
3236 sin_dst = (struct sockaddr_in *)(&sr->dest);
3237 ip->saddr = sin_dst->sin_addr.s_addr;
3238 sin_src = (struct sockaddr_in *)(&sr->source);
3239 ip->daddr = sin_src->sin_addr.s_addr;
3241 ip->check = 0;
3242 ip->check = in_cksum((u_short*)ip, sizeof(struct iphdr), ip->check);
3243 #else
3244 ip->ip_v = IPVERSION;
3245 ip->ip_hl = sizeof(struct ip) >> 2;
3247 ip->ip_tos = 0;
3249 #ifdef __OpenBSD__
3250 ip->ip_len = htons(udplen + sizeof(struct ip));
3251 #else
3252 ip->ip_len = udplen + sizeof(struct ip);
3253 #endif
3255 ip->ip_id = arc4random();
3257 #ifdef __OpenBSD__
3258 ip->ip_off = htons(IP_DF);
3259 #else
3260 ip->ip_off = IP_DF;
3261 #endif
3263 ip->ip_ttl = 64;
3264 ip->ip_p = IPPROTO_UDP;
3266 sin_src = (struct sockaddr_in *)(&sr->source);
3267 ip->ip_dst.s_addr = sin_src->sin_addr.s_addr;
3268 sin_dst = (struct sockaddr_in *)(&sr->dest);
3269 ip->ip_src.s_addr = sin_dst->sin_addr.s_addr;
3271 ip->ip_sum = 0;
3272 ip->ip_sum = in_cksum((u_short*)ip, sizeof(struct ip), ip->ip_sum);
3273 #endif
3275 #ifdef __linux__
3277 udp->source = sin_dst->sin_port;
3278 udp->dest = sin_src->sin_port;
3279 udp->len = htons(udplen);
3280 udp->check = 0;
3282 udp->check = udp_cksum(ip, udp, udplen);
3284 #else
3285 udp->uh_sport = sin_dst->sin_port;
3286 udp->uh_dport = sin_src->sin_port;
3287 udp->uh_ulen = htons(udplen);
3288 udp->uh_sum = 0;
3290 udp->uh_sum = udp_cksum(ip, udp, udplen);
3291 #endif
3293 #ifdef __linux__
3294 if ((retlen = sendto(so, buf, sizeof(struct iphdr) + udplen, 0, (struct sockaddr *)(&sr->dest), sizeof(struct sockaddr))) < 0) {
3295 #else
3296 if ((retlen = sendto(so, buf, sizeof(struct ip) + udplen, 0, (struct sockaddr *)(&sr->dest), sizeof(struct sockaddr))) < 0) {
3297 #endif
3298 dolog(LOG_ERR, "sendto: %s\n", strerror(errno));
3301 return (retlen);
3305 * REPLY_RAW6 - do an ipv6 raw reply
3309 int
3310 reply_raw6(int so, char *reply, int outlen, struct recurses *sr)
3312 char buf[2048];
3313 char csum[2048];
3315 struct udphdr *udp;
3316 int udplen = outlen + sizeof(struct udphdr);
3317 struct sockaddr_in6 *sin_src, *sin_dst;
3318 struct sockaddr_in6 sin6;
3320 struct ip6_hdr_pseudo *pseudo;
3321 int retlen = -1;
3323 udp = (struct udphdr *)&buf[0];
3324 memcpy(&buf[sizeof(struct udphdr)], reply, outlen);
3326 sin_src = (struct sockaddr_in6 *)(&sr->source);
3327 sin_dst = (struct sockaddr_in6 *)(&sr->dest);
3329 #ifdef __linux__
3330 udp->source = sin_dst->sin6_port;
3331 udp->dest = sin_src->sin6_port;
3332 udp->len = htons(udplen);
3333 udp->check = 0;
3334 #else
3335 udp->uh_sport = sin_dst->sin6_port;
3336 udp->uh_dport = sin_src->sin6_port;
3337 udp->uh_ulen = htons(udplen);
3338 udp->uh_sum = 0;
3339 #endif
3341 memset(&sin6, 0, sizeof(sin6));
3342 sin6.sin6_family = AF_INET6;
3343 memcpy((char *)&sin6.sin6_addr, (char *)&sin_dst->sin6_addr, sizeof(struct in6_addr));
3345 if (bind(so, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
3346 dolog(LOG_ERR, "bind6: %s\n", strerror(errno));
3347 return (retlen);
3350 memset(&sin6, 0, sizeof(sin6));
3351 sin6.sin6_family = AF_INET6;
3352 memcpy(&sin6.sin6_addr, (char *)&sin_src->sin6_addr, sizeof(struct in6_addr));
3353 sin6.sin6_port = sin_src->sin6_port;
3354 #ifndef __linux__
3355 sin6.sin6_len = sizeof(struct sockaddr_in6);
3356 #endif
3358 pseudo = (struct ip6_hdr_pseudo *)&csum[0];
3359 pseudo->ip6ph_nxt = IPPROTO_UDP;
3360 pseudo->ip6ph_len = htons(udplen);
3361 memcpy((char *)&pseudo->ip6ph_src, &sin_dst->sin6_addr, sizeof(struct in6_addr));
3362 memcpy((char *)&pseudo->ip6ph_dst, &sin_src->sin6_addr, sizeof(struct in6_addr));
3364 memcpy((char *)&csum[sizeof(struct ip6_hdr_pseudo)], udp, udplen);
3366 #ifdef __linux__
3367 udp->check = in_cksum((u_short *)&csum[0], sizeof(struct ip6_hdr_pseudo) + udplen, 0);
3368 #else
3369 udp->uh_sum = in_cksum((u_short *)&csum[0], sizeof(struct ip6_hdr_pseudo) + udplen, 0);
3370 #endif
3373 if ((retlen = sendto(so, buf, udplen, 0, (struct sockaddr *)(&sr->dest), sizeof(struct sockaddr_in6))) < 0) {
3374 dolog(LOG_ERR, "sendto: %s\n", strerror(errno));
3377 return (retlen);
3384 /* from print_udp.c */
3386 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
3387 * The Regents of the University of California. All rights reserved.
3389 * Redistribution and use in source and binary forms, with or without
3390 * modification, are permitted provided that: (1) source code distributions
3391 * retain the above copyright notice and this paragraph in its entirety, (2)
3392 * distributions including binary code include the above copyright notice and
3393 * this paragraph in its entirety in the documentation or other materials
3394 * provided with the distribution, and (3) all advertising materials mentioning
3395 * features or use of this software display the following acknowledgement:
3396 * ``This product includes software developed by the University of California,
3397 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
3398 * the University nor the names of its contributors may be used to endorse
3399 * or promote products derived from this software without specific prior
3400 * written permission.
3401 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
3402 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
3403 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
3406 static int
3407 #ifdef __linux__
3408 udp_cksum(const struct iphdr *ip, const struct udphdr *up, int len)
3409 #else
3410 udp_cksum(const struct ip *ip, const struct udphdr *up, int len)
3411 #endif
3413 union phu {
3414 struct phdr {
3415 u_int32_t src;
3416 u_int32_t dst;
3417 u_char mbz;
3418 u_char proto;
3419 u_int16_t len;
3420 } ph;
3421 u_int16_t pa[6];
3422 } phu;
3423 const u_int16_t *sp;
3424 u_int32_t sum;
3426 /* pseudo-header.. */
3427 phu.ph.len = htons((u_int16_t)len);
3428 phu.ph.mbz = 0;
3429 phu.ph.proto = IPPROTO_UDP;
3430 #ifdef __linux__
3431 memcpy(&phu.ph.src, &ip->saddr, sizeof(u_int32_t));
3432 memcpy(&phu.ph.dst, &ip->daddr, sizeof(u_int32_t));
3433 #else
3434 memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
3435 memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
3436 #endif
3438 sp = &phu.pa[0];
3439 sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5];
3441 return in_cksum((u_short *)up, len, sum);
3444 u_short
3445 in_cksum(const u_short *addr, register int len, int csum)
3447 int nleft = len;
3448 const u_short *w = addr;
3449 u_short answer;
3450 int sum = csum;
3453 * Our algorithm is simple, using a 32 bit accumulator (sum),
3454 * we add sequential 16 bit words to it, and at the end, fold
3455 * back all the carry bits from the top 16 bits into the lower
3456 * 16 bits.
3458 while (nleft > 1) {
3459 sum += *w++;
3460 nleft -= 2;
3462 if (nleft == 1)
3463 sum += htons(*(u_char *)w<<8);
3466 * add back carry outs from top 16 bits to low 16 bits
3468 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
3469 sum += (sum >> 16); /* add carry */
3470 answer = ~sum; /* truncate to 16 bits */
3471 return (answer);
3474 int
3475 reply_any(struct sreply *sreply)
3477 char *reply = sreply->replybuf;
3478 struct dns_header *odh;
3479 u_int16_t outlen;
3481 int so = sreply->so;
3482 char *buf = sreply->buf;
3483 int len = sreply->len;
3484 struct question *q = sreply->q;
3485 struct sockaddr *sa = sreply->sa;
3486 int salen = sreply->salen;
3487 int istcp = sreply->istcp;
3488 int replysize = 512;
3489 int retlen = -1;
3491 if (istcp) {
3492 replysize = 65535;
3495 if (q->edns0len > 512)
3496 replysize = q->edns0len;
3498 /* st */
3500 odh = (struct dns_header *)&reply[0];
3501 outlen = sizeof(struct dns_header);
3503 if (len > replysize) {
3504 return (retlen);
3507 /* copy question to reply */
3508 memcpy(reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
3509 /* blank query */
3510 memset((char *)&odh->query, 0, sizeof(u_int16_t));
3512 outlen += (q->hdr->namelen + 4);
3514 SET_DNS_REPLY(odh);
3515 if (sreply->sr == NULL)
3516 SET_DNS_AUTHORITATIVE(odh);
3517 else
3518 SET_DNS_RECURSION_AVAIL(odh);
3520 NTOHS(odh->query);
3522 odh->question = htons(1);
3523 odh->answer = 0;
3524 odh->nsrr = 0;
3525 odh->additional = 0;
3527 outlen = create_anyreply(sreply, (char *)reply, replysize, outlen, 1);
3528 if (outlen == 0) {
3529 return (retlen);
3532 if (q->edns0len) {
3533 /* tag on edns0 opt record */
3534 NTOHS(odh->additional);
3535 odh->additional++;
3536 HTONS(odh->additional);
3538 outlen = additional_opt(q, reply, replysize, outlen);
3541 if (sreply->sr != NULL) {
3542 retlen = reply_raw2(so, reply, outlen, sreply->sr);
3543 } else {
3544 if (istcp) {
3545 char *tmpbuf;
3546 u_int16_t *plen;
3548 tmpbuf = malloc(outlen + 2);
3549 if (tmpbuf == NULL) {
3550 dolog(LOG_INFO, "malloc: %s\n", strerror(errno));
3552 plen = (u_int16_t *)tmpbuf;
3553 *plen = htons(outlen);
3555 memcpy(&tmpbuf[2], reply, outlen);
3557 if ((retlen = send(so, tmpbuf, outlen + 2, 0)) < 0) {
3558 dolog(LOG_INFO, "send: %s\n", strerror(errno));
3560 free(tmpbuf);
3561 } else {
3562 if ((retlen = sendto(so, reply, outlen, 0, sa, salen)) < 0) {
3563 dolog(LOG_INFO, "sendto: %s\n", strerror(errno));
3568 return (retlen);
3572 * CREATE_ANYREPLY - pack an entire zone record into an any reply or axfr
3576 u_int16_t
3577 create_anyreply(struct sreply *sreply, char *reply, int rlen, int offset, int soa)
3579 int a_count, aaaa_count, ns_count, mx_count, srv_count, sshfp_count;
3580 int naptr_count;
3581 int tmplen, pos, mod;
3582 int ttlhack;
3583 struct answer {
3584 u_int16_t type; /* 0 */
3585 u_int16_t class; /* 2 */
3586 u_int32_t ttl; /* 4 */
3587 u_int16_t rdlength; /* 8 */
3588 char rdata[0]; /* 10 */
3589 } __packed;
3590 struct answer *answer;
3591 struct domain *sd = sreply->sd1;
3592 u_int8_t region = sreply->region;
3593 struct question *q = sreply->q;
3594 struct dns_header *odh = (struct dns_header *)reply;
3595 int labellen;
3596 char *label, *plabel;
3597 u_int32_t *soa_val;
3598 u_int16_t namelen;
3599 u_int16_t *mx_priority, *srv_priority, *srv_port, *srv_weight;
3600 u_int16_t *naptr_order, *naptr_preference;
3601 u_int8_t *sshfp_alg, *sshfp_fptype;
3602 char *name, *p;
3603 int i;
3605 if ((sd->flags & DOMAIN_HAVE_SOA) && soa) {
3606 NTOHS(odh->answer);
3607 odh->answer++;
3608 HTONS(odh->answer);
3610 if ((offset + q->hdr->namelen) > rlen) {
3611 goto truncate;
3614 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3615 offset += q->hdr->namelen;
3617 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3618 offset = tmplen;
3621 answer = (struct answer *)&reply[offset];
3623 answer->type = htons(DNS_TYPE_SOA);
3624 answer->class = htons(DNS_CLASS_IN);
3625 answer->ttl = htonl(sd->ttl);
3627 offset += 10; /* up to rdata length */
3629 label = sd->soa.nsserver;
3630 labellen = sd->soa.nsserver_len;
3632 plabel = label;
3634 /* copy label to reply */
3635 for (i = offset; i < rlen; i++) {
3636 if (i - offset == labellen)
3637 break;
3639 reply[i] = *plabel++;
3642 if (i >= rlen) {
3643 goto truncate;
3646 offset = i;
3648 /* compress the label if possible */
3649 if ((tmplen = compress_label((u_char*)reply, offset, labellen)) > 0) {
3650 offset = tmplen;
3653 label = sd->soa.responsible_person;
3654 labellen = sd->soa.rp_len;
3655 plabel = label;
3657 for (i = offset; i < rlen; i++) {
3658 if (i - offset == labellen)
3659 break;
3661 reply[i] = *plabel++;
3664 if (i >= rlen) {
3665 goto truncate;
3668 offset = i;
3670 /* 2 compress the label if possible */
3672 if ((tmplen = compress_label((u_char*)reply, offset, labellen)) > 0) {
3673 offset = tmplen;
3676 if ((offset + sizeof(sd->soa.serial)) > rlen) {
3677 goto truncate;
3680 soa_val = (u_int32_t *)&reply[offset];
3681 *soa_val = htonl(sd->soa.serial);
3682 offset += sizeof(sd->soa.serial);
3684 if ((offset + sizeof(sd->soa.refresh)) > rlen) {
3685 goto truncate;
3688 soa_val = (u_int32_t *)&reply[offset];
3689 *soa_val = htonl(sd->soa.refresh);
3690 offset += sizeof(sd->soa.refresh);
3692 if ((offset + sizeof(sd->soa.retry)) > rlen) {
3693 goto truncate;
3696 soa_val = (u_int32_t *)&reply[offset];
3697 *soa_val = htonl(sd->soa.retry);
3698 offset += sizeof(sd->soa.retry);
3700 if ((offset + sizeof(sd->soa.expire)) > rlen) {
3701 goto truncate;
3704 soa_val = (u_int32_t *)&reply[offset];
3705 *soa_val = htonl(sd->soa.expire);
3706 offset += sizeof(sd->soa.expire);
3708 if ((offset + sizeof(sd->soa.minttl)) > rlen) {
3709 goto truncate;
3712 soa_val = (u_int32_t *)&reply[offset];
3713 *soa_val = htonl(sd->soa.minttl);
3714 offset += sizeof(sd->soa.minttl);
3716 answer->rdlength = htons(&reply[offset] - answer->rdata);
3719 if (sd->flags & DOMAIN_HAVE_NS) {
3720 ns_count = 0;
3721 mod = sd->ns_count;
3722 pos = sd->ns_ptr;
3724 do {
3725 if (offset + q->hdr->namelen > rlen)
3726 goto truncate;
3728 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3729 offset += q->hdr->namelen;
3731 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3732 offset = tmplen;
3735 answer = (struct answer *)&reply[offset];
3737 answer->type = htons(DNS_TYPE_NS);
3738 answer->class = htons(DNS_CLASS_IN);
3739 answer->ttl = htonl(sd->ttl);
3741 answer->rdlength = htons(namelen);
3743 offset += 10; /* struct answer */
3745 name = sd->ns[pos % mod].nsserver;
3746 namelen = sd->ns[pos % mod].nslen;
3748 if (offset + namelen > rlen)
3749 goto truncate;
3751 memcpy((char *)&answer->rdata, (char *)name, namelen);
3753 offset += namelen;
3755 /* compress the label if possible */
3756 if ((tmplen = compress_label((u_char*)reply, offset, namelen)) > 0) {
3757 offset = tmplen;
3760 answer->rdlength = htons(&reply[offset] - answer->rdata);
3763 /* can we afford to write another header? if no truncate */
3764 if (sd->ns_count > 1 && (offset + sd->ns[pos % mod].nslen) > rlen) {
3765 goto truncate;
3768 pos++;
3770 } while (++ns_count < RECORD_COUNT && --sd->ns_count);
3772 NTOHS(odh->answer);
3773 odh->answer += ns_count;
3774 HTONS(odh->answer);
3777 if (sd->flags & DOMAIN_HAVE_PTR) {
3778 NTOHS(odh->answer);
3779 odh->answer++;
3780 HTONS(odh->answer);
3782 if ((offset + q->hdr->namelen) > rlen) {
3783 goto truncate;
3786 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3787 offset += q->hdr->namelen;
3789 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3790 offset = tmplen;
3793 answer = (struct answer *)&reply[offset];
3795 answer->type = htons(DNS_TYPE_PTR);
3796 answer->class = htons(DNS_CLASS_IN);
3797 answer->ttl = htonl(sd->ttl);
3799 offset += 10; /* up to rdata length */
3801 label = sd->ptr;
3802 labellen = sd->ptrlen;
3804 plabel = label;
3806 /* copy label to reply */
3807 for (i = offset; i < rlen; i++) {
3808 if (i - offset == labellen)
3809 break;
3811 reply[i] = *plabel++;
3814 if (i >= rlen) {
3815 goto truncate;
3818 offset = i;
3820 /* compress the label if possible */
3821 if ((tmplen = compress_label((u_char*)reply, offset, labellen)) > 0) {
3822 offset = tmplen;
3825 answer->rdlength = htons(&reply[offset] - answer->rdata);
3827 if (sd->flags & DOMAIN_HAVE_MX) {
3828 mx_count = 0;
3829 do {
3830 if ((offset + q->hdr->namelen) > rlen) {
3831 goto truncate;
3834 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3835 offset += q->hdr->namelen;
3837 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3838 offset = tmplen;
3842 if (offset + 12 > rlen)
3843 goto truncate;
3845 answer = (struct answer *)&reply[offset];
3847 answer->type = htons(DNS_TYPE_MX);
3848 answer->class = htons(DNS_CLASS_IN);
3849 answer->ttl = htonl(sd->ttl);
3850 answer->rdlength = htons(sizeof(u_int16_t) + sd->mx[mx_count].exchangelen);
3852 offset += 10; /* up to rdata length */
3854 mx_priority = (u_int16_t *)&reply[offset];
3855 *mx_priority = htons(sd->mx[mx_count].preference);
3857 offset += 2;
3859 if (offset + sd->mx[mx_count].exchangelen > rlen)
3860 goto truncate;
3862 memcpy((char *)&reply[offset], (char *)sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
3864 offset += sd->mx[mx_count].exchangelen;
3866 if ((tmplen = compress_label((u_char*)reply, offset, sd->mx[mx_count].exchangelen)) > 0) {
3867 offset = tmplen;
3870 /* can we afford to write another header? if no truncate */
3871 if (sd->mx_count > 1 && (offset + 12 + 2 + sd->mx[mx_count].exchangelen) > rlen) {
3872 goto truncate;
3875 answer->rdlength = htons(&reply[offset] - answer->rdata);
3876 } while (++mx_count < RECORD_COUNT && --sd->mx_count);
3878 NTOHS(odh->answer);
3879 odh->answer += mx_count;
3880 HTONS(odh->answer);
3883 if (sd->flags & DOMAIN_HAVE_SPF) {
3884 NTOHS(odh->answer);
3885 odh->answer++;
3886 HTONS(odh->answer);
3888 if ((offset + q->hdr->namelen) > rlen) {
3889 goto truncate;
3892 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3893 offset += q->hdr->namelen;
3895 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3896 offset = tmplen;
3899 answer = (struct answer *)&reply[offset];
3901 answer->type = htons(DNS_TYPE_SPF);
3902 answer->class = htons(DNS_CLASS_IN);
3903 answer->ttl = htonl(sd->ttl);
3905 offset += 10; /* up to rdata length */
3909 if (offset + sd->spflen + 1 > rlen)
3910 goto truncate;
3912 p = (char *)&answer->rdata;
3913 *p = sd->spflen;
3914 memcpy((p + 1), sd->spf, sd->spflen);
3915 offset += (sd->spflen + 1);
3917 answer->rdlength = htons(sd->spflen + 1);
3920 if (sd->flags & DOMAIN_HAVE_TXT) {
3921 NTOHS(odh->answer);
3922 odh->answer++;
3923 HTONS(odh->answer);
3925 if ((offset + q->hdr->namelen) > rlen) {
3926 goto truncate;
3929 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3930 offset += q->hdr->namelen;
3932 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3933 offset = tmplen;
3936 answer = (struct answer *)&reply[offset];
3938 answer->type = htons(DNS_TYPE_TXT);
3939 answer->class = htons(DNS_CLASS_IN);
3940 answer->ttl = htonl(sd->ttl);
3942 offset += 10; /* up to rdata length */
3946 if (offset + sd->txtlen + 1 > rlen)
3947 goto truncate;
3949 p = (char *)&answer->rdata;
3950 *p = sd->txtlen;
3951 memcpy((p + 1), sd->txt, sd->txtlen);
3952 offset += (sd->txtlen + 1);
3954 answer->rdlength = htons(sd->txtlen + 1);
3957 if (sd->flags & DOMAIN_HAVE_SSHFP) {
3958 sshfp_count = 0;
3959 do {
3960 if ((offset + q->hdr->namelen) > rlen) {
3961 goto truncate;
3964 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
3965 offset += q->hdr->namelen;
3967 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
3968 offset = tmplen;
3972 if (offset + 12 > rlen)
3973 goto truncate;
3975 answer = (struct answer *)&reply[offset];
3977 answer->type = htons(DNS_TYPE_SSHFP);
3978 answer->class = htons(DNS_CLASS_IN);
3979 answer->ttl = htonl(sd->ttl);
3980 answer->rdlength = htons((2 * sizeof(u_int8_t)) + sd->sshfp[sshfp_count].fplen);
3982 offset += 10; /* up to rdata length */
3984 sshfp_alg = (u_int8_t *)&reply[offset];
3985 *sshfp_alg = sd->sshfp[sshfp_count].algorithm;
3987 offset++;
3989 sshfp_fptype = (u_int8_t *)&reply[offset];
3990 *sshfp_fptype = sd->sshfp[sshfp_count].fptype;
3992 offset++;
3994 if (offset + sd->sshfp[sshfp_count].fplen > rlen)
3995 goto truncate;
3997 memcpy((char *)&reply[offset], (char *)sd->sshfp[sshfp_count].fingerprint, sd->sshfp[sshfp_count].fplen);
3999 offset += sd->sshfp[sshfp_count].fplen;
4001 /* can we afford to write another header? if no truncate */
4002 if (sd->sshfp_count > 1 && (offset + 12 + 2 + sd->sshfp[sshfp_count].fplen) > rlen) {
4003 goto truncate;
4006 answer->rdlength = htons(&reply[offset] - answer->rdata);
4007 } while (++sshfp_count < RECORD_COUNT && --sd->sshfp_count);
4009 NTOHS(odh->answer);
4010 odh->answer += sshfp_count;
4011 HTONS(odh->answer);
4014 if (sd->flags & DOMAIN_HAVE_NAPTR) {
4015 naptr_count = 0;
4016 do {
4017 if ((offset + q->hdr->namelen) > rlen) {
4018 goto truncate;
4021 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
4022 offset += q->hdr->namelen;
4024 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
4025 offset = tmplen;
4029 if (offset + 12 > rlen)
4030 goto truncate;
4032 answer = (struct answer *)&reply[offset];
4034 answer->type = htons(DNS_TYPE_NAPTR);
4035 answer->class = htons(DNS_CLASS_IN);
4036 answer->ttl = htonl(sd->ttl);
4037 answer->rdlength = htons((2 * sizeof(u_int16_t)) + sd->naptr[naptr_count].flagslen + 1 + sd->naptr[naptr_count].serviceslen + 1 + sd->naptr[naptr_count].regexplen + 1 + sd->naptr[naptr_count].replacementlen);
4039 offset += 10; /* up to rdata length */
4041 naptr_order = (u_int16_t *)&reply[offset];
4042 *naptr_order = htons(sd->naptr[naptr_count].order);
4044 offset += 2;
4046 naptr_preference = (u_int16_t *)&reply[offset];
4047 *naptr_preference = htons(sd->naptr[naptr_count].preference);
4049 offset += 2;
4051 /* flags */
4052 if (offset + sd->naptr[naptr_count].flagslen + 1> rlen)
4053 goto truncate;
4055 reply[offset] = sd->naptr[naptr_count].flagslen;
4056 offset++;
4058 memcpy((char *)&reply[offset], (char *)sd->naptr[naptr_count].flags, sd->naptr[naptr_count].flagslen);
4060 offset += sd->naptr[naptr_count].flagslen;
4061 /* services */
4062 if (offset + sd->naptr[naptr_count].serviceslen + 1> rlen)
4063 goto truncate;
4065 reply[offset] = sd->naptr[naptr_count].serviceslen;
4066 offset++;
4068 memcpy((char *)&reply[offset], (char *)sd->naptr[naptr_count].services, sd->naptr[naptr_count].serviceslen);
4070 offset += sd->naptr[naptr_count].serviceslen;
4071 /* regexp */
4072 if (offset + sd->naptr[naptr_count].regexplen + 1> rlen)
4073 goto truncate;
4075 reply[offset] = sd->naptr[naptr_count].regexplen;
4076 offset++;
4078 memcpy((char *)&reply[offset], (char *)sd->naptr[naptr_count].regexp, sd->naptr[naptr_count].regexplen);
4080 offset += sd->naptr[naptr_count].regexplen;
4081 /* replacement */
4082 if (offset + sd->naptr[naptr_count].replacementlen > rlen)
4083 goto truncate;
4085 memcpy((char *)&reply[offset], (char *)sd->naptr[naptr_count].replacement, sd->naptr[naptr_count].replacementlen);
4087 offset += sd->naptr[naptr_count].replacementlen;
4089 if ((tmplen = compress_label((u_char*)reply, offset, sd->naptr[naptr_count].replacementlen)) > 0) {
4090 offset = tmplen;
4093 /* can we afford to write another header? if no truncate */
4094 if (sd->naptr_count > naptr_count && (offset + 12 + 4 + sd->naptr[naptr_count + 1].flagslen + 1) > rlen) {
4095 goto truncate;
4098 answer->rdlength = htons(&reply[offset] - answer->rdata);
4099 } while (++naptr_count < RECORD_COUNT && --sd->naptr_count);
4101 NTOHS(odh->answer);
4102 odh->answer += naptr_count;
4103 HTONS(odh->answer);
4106 if (sd->flags & DOMAIN_HAVE_SRV) {
4107 srv_count = 0;
4108 do {
4109 if ((offset + q->hdr->namelen) > rlen) {
4110 goto truncate;
4113 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
4114 offset += q->hdr->namelen;
4116 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
4117 offset = tmplen;
4121 if (offset + 12 > rlen)
4122 goto truncate;
4124 answer = (struct answer *)&reply[offset];
4126 answer->type = htons(DNS_TYPE_SRV);
4127 answer->class = htons(DNS_CLASS_IN);
4128 answer->ttl = htonl(sd->ttl);
4129 answer->rdlength = htons((3 * sizeof(u_int16_t)) + sd->srv[srv_count].targetlen);
4131 offset += 10; /* up to rdata length */
4133 srv_priority = (u_int16_t *)&reply[offset];
4134 *srv_priority = htons(sd->srv[srv_count].priority);
4136 offset += 2;
4138 srv_weight = (u_int16_t *)&reply[offset];
4139 *srv_weight = htons(sd->srv[srv_count].weight);
4141 offset += 2;
4143 srv_port = (u_int16_t *)&reply[offset];
4144 *srv_port = htons(sd->srv[srv_count].port);
4146 offset += 2;
4148 if (offset + sd->srv[srv_count].targetlen > rlen)
4149 goto truncate;
4151 memcpy((char *)&reply[offset], (char *)sd->srv[srv_count].target, sd->srv[srv_count].targetlen);
4153 offset += sd->srv[srv_count].targetlen;
4155 if ((tmplen = compress_label((u_char*)reply, offset, sd->srv[srv_count].targetlen)) > 0) {
4156 offset = tmplen;
4159 /* can we afford to write another header? if no truncate */
4160 if (sd->srv_count > 1 && (offset + 12 + 6 + sd->srv[srv_count].targetlen) > rlen) {
4161 goto truncate;
4164 answer->rdlength = htons(&reply[offset] - answer->rdata);
4165 } while (++srv_count < RECORD_COUNT && --sd->srv_count);
4167 NTOHS(odh->answer);
4168 odh->answer += srv_count;
4169 HTONS(odh->answer);
4173 if (sd->flags & DOMAIN_HAVE_CNAME) {
4174 NTOHS(odh->answer);
4175 odh->answer++;
4176 HTONS(odh->answer);
4178 if ((offset + q->hdr->namelen) > rlen) {
4179 goto truncate;
4182 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
4183 offset += q->hdr->namelen;
4185 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
4186 offset = tmplen;
4189 answer = (struct answer *)&reply[offset];
4191 answer->type = htons(DNS_TYPE_CNAME);
4192 answer->class = htons(DNS_CLASS_IN);
4193 answer->ttl = htonl(sd->ttl);
4195 offset += 10; /* up to rdata length */
4197 label = sd->cname;
4198 labellen = sd->cnamelen;
4200 plabel = label;
4202 /* copy label to reply */
4203 for (i = offset; i < rlen; i++) {
4204 if (i - offset == labellen)
4205 break;
4207 reply[i] = *plabel++;
4210 if (i >= rlen) {
4211 goto truncate;
4214 offset = i;
4216 /* compress the label if possible */
4217 if ((tmplen = compress_label((u_char*)reply, offset, labellen)) > 0) {
4218 offset = tmplen;
4221 answer->rdlength = htons(&reply[offset] - answer->rdata);
4223 if (sd->flags & DOMAIN_HAVE_A) {
4224 /* if we aren't a balance record our region code is 0xff so check */
4225 if (sd->region[sd->a_ptr] != 0xff) {
4226 ttlhack = 1;
4229 a_count = 0;
4230 pos = sd->a_ptr;
4231 mod = sd->a_count;
4233 do {
4235 * skip records that are not in the needed region
4237 if (ttlhack && sd->region[pos % mod] != region) {
4238 pos++;
4239 continue;
4242 if (offset + q->hdr->namelen > rlen)
4243 goto truncate;
4245 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
4246 offset += q->hdr->namelen;
4248 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
4249 offset = tmplen;
4252 answer = (struct answer *)&reply[offset];
4254 answer->type = htons(DNS_TYPE_A);
4255 answer->class = htons(DNS_CLASS_IN);
4256 answer->ttl = htonl(sd->ttl);
4257 answer->rdlength = htons(sizeof(in_addr_t));
4259 memcpy((char *)&answer->rdata, (char *)&sd->a[pos++ % mod],
4260 sizeof(in_addr_t));
4262 a_count++;
4263 offset += 14;
4265 /* can we afford to write another header? if no truncate */
4266 if (sd->a_count > 1 && offset + 16 > rlen) {
4267 goto truncate;
4270 answer = (struct answer *)&reply[offset];
4272 } while (a_count < RECORD_COUNT && --sd->a_count);
4274 NTOHS(odh->answer);
4275 odh->answer += a_count;
4276 HTONS(odh->answer);
4278 if (sd->flags & DOMAIN_HAVE_AAAA) {
4279 NTOHS(odh->answer);
4280 odh->answer += sd->aaaa_count;
4281 HTONS(odh->answer);
4283 pos = sd->aaaa_ptr;
4284 mod = sd->aaaa_count;
4286 aaaa_count = 0;
4288 do {
4289 if (offset + q->hdr->namelen > rlen)
4290 goto truncate;
4292 memcpy(&reply[offset], q->hdr->name, q->hdr->namelen);
4293 offset += q->hdr->namelen;
4295 if ((tmplen = compress_label((u_char*)reply, offset, q->hdr->namelen)) > 0) {
4296 offset = tmplen;
4299 answer = (struct answer *)&reply[offset];
4301 answer->type = htons(DNS_TYPE_AAAA);
4302 answer->class = htons(DNS_CLASS_IN);
4303 answer->ttl = htonl(sd->ttl);
4304 answer->rdlength = htons(sizeof(struct in6_addr));
4305 offset += 10;
4307 memcpy((char *)&reply[offset] ,(char *)&sd->aaaa[pos++ % mod], sizeof(struct in6_addr));
4308 offset += 16;
4310 /* can we afford to write another header? if no truncate */
4311 if (sd->aaaa_count > 1 && offset + 28 > rlen) {
4312 goto truncate;
4315 aaaa_count++;
4316 } while (aaaa_count < RECORD_COUNT && --sd->aaaa_count);
4320 return (offset);
4322 truncate:
4323 NTOHS(odh->query);
4324 SET_DNS_TRUNCATION(odh);
4325 HTONS(odh->query);
4327 return (offset);