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 int additional_a(char *, int, struct domain *, char *, int, int, int *);
33 int additional_aaaa(char *, int, struct domain *, char *, int, int, int *);
34 int additional_mx(char *, int, struct domain *, char *, int, int, int *);
35 int additional_opt(struct question *, char *, int, int);
36 int additional_ptr(char *, int, struct domain *, char *, int, int, int *);
38 extern int compress_label(u_char *, int, int);
40 static const char rcsid[] = "$Id: additional.c,v 1.17 2014/05/18 17:14:05 pjp Exp $";
43 /*
44 * ADDITIONAL_A - tag on an additional set of A records to packet
45 */
47 int
48 additional_a(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
49 {
50 int a_count;
51 int tmplen;
52 int rroffset = offset;
54 struct answer {
55 u_int16_t type;
56 u_int16_t class;
57 u_int32_t ttl;
58 u_int16_t rdlength; /* 12 */
59 in_addr_t rdata; /* 16 */
60 } __attribute__((packed));
62 struct answer *answer;
64 *retcount = 0;
66 /*
67 * We loop through our sd->a entries starting at the ptr offset
68 * first in the first loop and at the beginning until the ptr
69 * in the last loop. This will shift answers based on a_ptr.
70 */
72 for (a_count = sd->a_ptr; a_count < sd->a_count; a_count++) {
73 rroffset = offset;
74 if ((offset + namelen) > replylen)
75 goto out;
77 memcpy(&reply[offset], name, namelen);
78 offset += namelen;
79 tmplen = compress_label((u_char*)reply, offset, namelen);
81 if (tmplen != 0) {
82 offset = tmplen;
83 }
84 if ((offset + sizeof(struct answer)) > replylen) {
85 offset = rroffset;
86 goto out;
87 }
89 answer = (struct answer *)&reply[offset];
91 answer->type = htons(DNS_TYPE_A);
92 answer->class = htons(DNS_CLASS_IN);
93 answer->ttl = htonl(sd->ttl);
95 answer->rdlength = htons(sizeof(in_addr_t));
97 memcpy((char *)&answer->rdata, (char *)&sd->a[a_count], sizeof(in_addr_t));
98 offset += sizeof(struct answer);
99 (*retcount)++;
103 for (a_count = 0; a_count < sd->a_ptr; a_count++) {
104 rroffset = offset;
105 if ((offset + namelen) > replylen)
106 goto out;
108 memcpy(&reply[offset], name, namelen);
109 offset += namelen;
110 tmplen = compress_label((u_char*)reply, offset, namelen);
112 if (tmplen != 0) {
113 offset = tmplen;
115 if ((offset + sizeof(struct answer)) > replylen) {
116 offset = rroffset;
117 goto out;
120 answer = (struct answer *)&reply[offset];
122 answer->type = htons(DNS_TYPE_A);
123 answer->class = htons(DNS_CLASS_IN);
124 answer->ttl = htonl(sd->ttl);
126 answer->rdlength = htons(sizeof(in_addr_t));
128 memcpy((char *)&answer->rdata, (char *)&sd->a[a_count], sizeof(in_addr_t));
129 offset += sizeof(struct answer);
130 (*retcount)++;
134 out:
135 return (offset);
139 /*
140 * ADDITIONAL_AAAA - tag on an additional set of AAAA records to packet
141 */
143 int
144 additional_aaaa(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
146 int aaaa_count;
147 int tmplen;
148 int rroffset = offset;
150 struct answer {
151 u_int16_t type;
152 u_int16_t class;
153 u_int32_t ttl;
154 u_int16_t rdlength;
155 struct in6_addr rdata;
156 } __attribute__((packed));
158 struct answer *answer;
160 *retcount = 0;
162 /*
163 * We loop through our sd->aaaa entries starting at the ptr offset
164 * first in the first loop and at the beginning until the ptr
165 * in the last loop. This will shift answers based on a_ptr.
166 */
168 for (aaaa_count = sd->aaaa_ptr; aaaa_count < sd->aaaa_count; aaaa_count++) {
169 rroffset = offset;
170 if ((offset + namelen) > replylen)
171 goto out;
173 memcpy(&reply[offset], name, namelen);
174 offset += namelen;
175 tmplen = compress_label((u_char*)reply, offset, namelen);
177 if (tmplen != 0) {
178 offset = tmplen;
181 if ((offset + sizeof(struct answer)) > replylen) {
182 offset = rroffset;
183 goto out;
186 answer = (struct answer *)&reply[offset];
188 answer->type = htons(DNS_TYPE_AAAA);
189 answer->class = htons(DNS_CLASS_IN);
190 answer->ttl = htonl(sd->ttl);
192 answer->rdlength = htons(sizeof(struct in6_addr));
194 memcpy((char *)&answer->rdata, (char *)&sd->aaaa[aaaa_count], sizeof(struct in6_addr));
195 offset += sizeof(struct answer);
196 (*retcount)++;
200 for (aaaa_count = 0; aaaa_count < sd->aaaa_ptr; aaaa_count++) {
201 rroffset = offset;
202 if ((offset + namelen) > replylen)
203 goto out;
206 memcpy(&reply[offset], name, namelen);
207 offset += namelen;
208 tmplen = compress_label((u_char*)reply, offset, namelen);
210 if (tmplen != 0) {
211 offset = tmplen;
213 if ((offset + sizeof(struct answer)) > replylen) {
214 offset = rroffset;
215 goto out;
218 answer = (struct answer *)&reply[offset];
220 answer->type = htons(DNS_TYPE_AAAA);
221 answer->class = htons(DNS_CLASS_IN);
222 answer->ttl = htonl(sd->ttl);
224 answer->rdlength = htons(sizeof(struct in6_addr));
227 memcpy((char *)&answer->rdata, (char *)&sd->aaaa[aaaa_count], sizeof(struct in6_addr));
228 offset += sizeof(struct answer);
229 (*retcount)++;
233 out:
234 return (offset);
238 /*
239 * ADDITIONAL_MX() - replies a DNS question (*q) on socket (so)
241 */
243 int
244 additional_mx(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
246 int mx_count;
247 int tmplen;
248 int rroffset = offset;
250 struct answer {
251 u_int16_t type;
252 u_int16_t class;
253 u_int32_t ttl;
254 u_int16_t rdlength;
255 u_int16_t mx_priority;
256 } __attribute__((packed));
258 struct answer *answer;
260 *retcount = 0;
262 /*
263 * We loop through our sd->mx entries starting at the ptr offset
264 * first in the first loop and at the beginning until the ptr
265 * in the last loop. This will shift answers based on mx_ptr.
266 */
268 for (mx_count = sd->mx_ptr; mx_count < sd->mx_count; mx_count++) {
269 rroffset = offset;
271 if ((offset + namelen) > replylen)
272 goto out;
274 memcpy(&reply[offset], name, namelen);
275 offset += namelen;
276 tmplen = compress_label((u_char*)reply, offset, namelen);
278 if (tmplen != 0) {
279 offset = tmplen;
282 if ((offset + sizeof(struct answer)) > replylen) {
283 offset = rroffset;
284 goto out;
287 answer = (struct answer *)&reply[offset];
289 answer->type = htons(DNS_TYPE_MX);
290 answer->class = htons(DNS_CLASS_IN);
291 answer->ttl = htonl(sd->ttl);
292 answer->mx_priority = htons(sd->mx[mx_count].preference);
294 offset += sizeof(struct answer);
296 if ((offset + sd->mx[mx_count].exchangelen) > replylen) {
297 offset = rroffset;
298 goto out;
301 memcpy((char *)&reply[offset], (char *)sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
303 offset += sd->mx[mx_count].exchangelen;
304 tmplen = compress_label((u_char*)reply, offset, sd->mx[mx_count].exchangelen);
306 if (tmplen != 0) {
307 answer->rdlength = htons((sd->mx[mx_count].exchangelen - (offset - tmplen)) + sizeof(u_int16_t));
308 offset = tmplen;
309 } else
310 answer->rdlength = htons(sd->mx[mx_count].exchangelen + sizeof(u_int16_t));
313 (*retcount)++;
317 for (mx_count = 0; mx_count < sd->mx_ptr; mx_count++) {
318 rroffset = offset;
320 if ((offset + namelen) > replylen)
321 goto out;
324 memcpy(&reply[offset], name, namelen);
325 offset += namelen;
326 tmplen = compress_label((u_char*)reply, offset, namelen);
328 if (tmplen != 0) {
329 offset = tmplen;
332 if ((offset + sizeof(struct answer)) > replylen) {
333 offset = rroffset;
334 goto out;
337 answer = (struct answer *)&reply[offset];
339 answer->type = htons(DNS_TYPE_A);
340 answer->class = htons(DNS_CLASS_IN);
341 answer->ttl = htonl(sd->ttl);
343 offset += sizeof(struct answer);
345 if ((offset + sd->mx[mx_count].exchangelen) > replylen) {
346 offset = rroffset;
347 goto out;
350 memcpy((char *)&reply[offset], (char *)sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
352 offset += sd->mx[mx_count].exchangelen;
353 tmplen = compress_label((u_char *)reply, offset, sd->mx[mx_count].exchangelen);
355 if (tmplen != 0) {
357 answer->rdlength = htons((sd->mx[mx_count].exchangelen - (offset - tmplen)) + sizeof(u_int16_t));
358 offset = tmplen;
359 } else
360 answer->rdlength = htons(sd->mx[mx_count].exchangelen + sizeof(u_int16_t));
362 (*retcount)++;
366 out:
367 return (offset);
371 /*
372 * ADDITIONAL_PTR() - replies a DNS question (*q) on socket (so)
374 */
377 int
378 additional_ptr(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
380 int tmplen;
381 int rroffset = offset;
383 struct answer {
384 u_int16_t type;
385 u_int16_t class;
386 u_int32_t ttl;
387 u_int16_t rdlength;
388 } __attribute__((packed));
390 struct answer *answer;
392 *retcount = 0;
395 if ((offset + namelen) > replylen)
396 goto out;
398 memcpy(&reply[offset], name, namelen);
399 offset += namelen;
400 tmplen = compress_label((u_char*)reply, offset, namelen);
402 if (tmplen != 0) {
403 offset = tmplen;
406 if ((offset + sizeof(struct answer)) > replylen) {
407 offset = rroffset;
408 goto out;
411 answer = (struct answer *)&reply[offset];
413 answer->type = htons(DNS_TYPE_PTR);
414 answer->class = htons(DNS_CLASS_IN);
415 answer->ttl = htonl(sd->ttl);
417 offset += sizeof(struct answer);
419 if ((offset + sd->ptrlen) > replylen) {
420 offset = rroffset;
421 goto out;
424 memcpy((char *)&reply[offset], (char *)sd->ptr, sd->ptrlen);
426 offset += sd->ptrlen;
427 tmplen = compress_label((u_char*)reply, offset, sd->ptrlen);
429 if (tmplen != 0) {
430 answer->rdlength = htons(sd->ptrlen - (offset - tmplen));
431 offset = tmplen;
432 } else
433 answer->rdlength = htons(sd->ptrlen);
436 (*retcount)++;
438 out:
439 return (offset);
443 /*
444 * ADDITIONAL_OPT - tag on an additional EDNS0 (OPT) record to packet
445 */
447 int
448 additional_opt(struct question *question, char *reply, int replylen, int offset)
450 struct dns_optrr *answer;
452 if ((offset + sizeof(struct dns_optrr)) > replylen) {
453 goto out;
456 answer = (struct dns_optrr *)&reply[offset];
458 memset(answer->name, 0, sizeof(answer->name));
459 answer->type = htons(DNS_TYPE_OPT);
460 answer->class = htons(question->edns0len);
461 answer->ttl = htonl(0);
463 answer->rdlen = htons(0);
465 offset += sizeof(struct dns_optrr);
467 out:
468 return (offset);