Annotation of embedaddon/dnsmasq/src/auth.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #ifdef HAVE_AUTH
20:
1.1.1.4 misho 21: static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
1.1 misho 22: {
1.1.1.4 misho 23: do {
24: if (!(list->flags & ADDRLIST_IPV6))
25: {
26: struct in_addr netmask, addr = addr_u->addr4;
27:
28: if (!(flag & F_IPV4))
29: continue;
30:
31: netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
32:
33: if (is_same_net(addr, list->addr.addr4, netmask))
34: return list;
35: }
36: else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
37: return list;
38:
39: } while ((list = list->next));
40:
41: return NULL;
42: }
1.1.1.2 misho 43:
1.1.1.4 misho 44: static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u)
45: {
46: if (!zone->subnet)
47: return NULL;
48:
49: return find_addrlist(zone->subnet, flag, addr_u);
50: }
1.1 misho 51:
1.1.1.4 misho 52: static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u)
53: {
54: if (!zone->exclude)
55: return NULL;
56:
57: return find_addrlist(zone->exclude, flag, addr_u);
1.1 misho 58: }
59:
1.1.1.4 misho 60: static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
1.1 misho 61: {
1.1.1.4 misho 62: if (find_exclude(zone, flag, addr_u))
63: return 0;
64:
65: /* No subnets specified, no filter */
1.1.1.2 misho 66: if (!zone->subnet)
67: return 1;
1.1 misho 68:
1.1.1.2 misho 69: return find_subnet(zone, flag, addr_u) != NULL;
1.1 misho 70: }
71:
1.1.1.2 misho 72: int in_zone(struct auth_zone *zone, char *name, char **cut)
1.1 misho 73: {
74: size_t namelen = strlen(name);
75: size_t domainlen = strlen(zone->domain);
76:
77: if (cut)
78: *cut = NULL;
79:
80: if (namelen >= domainlen &&
81: hostname_isequal(zone->domain, &name[namelen - domainlen]))
82: {
83:
84: if (namelen == domainlen)
85: return 1;
86:
87: if (name[namelen - domainlen - 1] == '.')
88: {
89: if (cut)
90: *cut = &name[namelen - domainlen - 1];
91: return 1;
92: }
93: }
94:
95: return 0;
96: }
97:
98:
1.1.1.3 misho 99: size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
100: int local_query, int do_bit, int have_pseudoheader)
1.1 misho 101: {
102: char *name = daemon->namebuff;
103: unsigned char *p, *ansp;
1.1.1.4 misho 104: int qtype, qclass, rc;
1.1 misho 105: int nameoffset, axfroffset = 0;
106: int q, anscount = 0, authcount = 0;
107: struct crec *crecp;
1.1.1.5 ! misho 108: int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
1.1 misho 109: struct auth_zone *zone = NULL;
1.1.1.2 misho 110: struct addrlist *subnet = NULL;
1.1 misho 111: char *cut;
112: struct mx_srv_record *rec, *move, **up;
113: struct txt_record *txt;
114: struct interface_name *intr;
115: struct naptr *na;
1.1.1.4 misho 116: union all_addr addr;
117: struct cname *a, *candidate;
118: unsigned int wclen;
1.1 misho 119:
120: if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
121: return 0;
1.1.1.2 misho 122:
1.1 misho 123: /* determine end of question section (we put answers there) */
124: if (!(ansp = skip_questions(header, qlen)))
125: return 0; /* bad packet */
126:
127: /* now process each question, answers go in RRs after the question */
128: p = (unsigned char *)(header+1);
129:
130: for (q = ntohs(header->qdcount); q != 0; q--)
131: {
1.1.1.4 misho 132: unsigned int flag = 0;
1.1 misho 133: int found = 0;
1.1.1.4 misho 134: int cname_wildcard = 0;
1.1 misho 135:
136: /* save pointer to name for copying into answers */
137: nameoffset = p - (unsigned char *)header;
138:
139: /* now extract name as .-concatenated string into name */
140: if (!extract_name(header, qlen, &p, name, 1, 4))
141: return 0; /* bad packet */
142:
143: GETSHORT(qtype, p);
144: GETSHORT(qclass, p);
145:
146: if (qclass != C_IN)
147: {
148: auth = 0;
1.1.1.5 ! misho 149: out_of_zone = 1;
1.1 misho 150: continue;
151: }
152:
1.1.1.3 misho 153: if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
154: (flag = in_arpa_name_2_addr(name, &addr)) &&
155: !local_query)
156: {
157: for (zone = daemon->auth_zones; zone; zone = zone->next)
158: if ((subnet = find_subnet(zone, flag, &addr)))
159: break;
160:
161: if (!zone)
1.1 misho 162: {
1.1.1.5 ! misho 163: out_of_zone = 1;
1.1.1.3 misho 164: auth = 0;
165: continue;
1.1.1.2 misho 166: }
1.1.1.3 misho 167: else if (qtype == T_SOA)
168: soa = 1, found = 1;
169: else if (qtype == T_NS)
170: ns = 1, found = 1;
171: }
1.1 misho 172:
1.1.1.3 misho 173: if (qtype == T_PTR && flag)
174: {
1.1.1.2 misho 175: intr = NULL;
176:
177: if (flag == F_IPV4)
178: for (intr = daemon->int_names; intr; intr = intr->next)
179: {
180: struct addrlist *addrlist;
181:
182: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1.1.1.4 misho 183: if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
1.1.1.2 misho 184: break;
185:
186: if (addrlist)
187: break;
188: else
189: while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
190: intr = intr->next;
191: }
192: else if (flag == F_IPV6)
193: for (intr = daemon->int_names; intr; intr = intr->next)
194: {
195: struct addrlist *addrlist;
196:
197: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1.1.1.4 misho 198: if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
1.1.1.2 misho 199: break;
200:
201: if (addrlist)
202: break;
203: else
204: while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
205: intr = intr->next;
206: }
207:
208: if (intr)
209: {
1.1.1.3 misho 210: if (local_query || in_zone(zone, intr->name, NULL))
1.1.1.2 misho 211: {
212: found = 1;
1.1.1.5 ! misho 213: log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
1.1.1.2 misho 214: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
215: daemon->auth_ttl, NULL,
216: T_PTR, C_IN, "d", intr->name))
217: anscount++;
1.1 misho 218: }
219: }
1.1.1.2 misho 220:
1.1 misho 221: if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
222: do {
223: strcpy(name, cache_get_name(crecp));
224:
225: if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
226: {
227: char *p = strchr(name, '.');
228: if (p)
229: *p = 0; /* must be bare name */
230:
231: /* add external domain */
1.1.1.3 misho 232: if (zone)
233: {
234: strcat(name, ".");
235: strcat(name, zone->domain);
236: }
1.1.1.5 ! misho 237: log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
1.1 misho 238: found = 1;
239: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
240: daemon->auth_ttl, NULL,
241: T_PTR, C_IN, "d", name))
242: anscount++;
243: }
1.1.1.3 misho 244: else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
1.1 misho 245: {
1.1.1.5 ! misho 246: log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
1.1 misho 247: found = 1;
248: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
249: daemon->auth_ttl, NULL,
250: T_PTR, C_IN, "d", name))
251: anscount++;
252: }
253: else
254: continue;
255:
256: } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
257:
1.1.1.5 ! misho 258: if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
! 259: {
! 260: log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
! 261: found = 1;
! 262:
! 263: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 264: daemon->auth_ttl, NULL,
! 265: T_PTR, C_IN, "d", name))
! 266: anscount++;
! 267: }
! 268:
1.1.1.2 misho 269: if (found)
270: nxdomain = 0;
271: else
1.1.1.5 ! misho 272: log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
1.1 misho 273:
274: continue;
275: }
276:
277: cname_restart:
1.1.1.3 misho 278: if (found)
279: /* NS and SOA .arpa requests have set found above. */
280: cut = NULL;
281: else
1.1 misho 282: {
1.1.1.3 misho 283: for (zone = daemon->auth_zones; zone; zone = zone->next)
284: if (in_zone(zone, name, &cut))
285: break;
286:
287: if (!zone)
288: {
1.1.1.5 ! misho 289: out_of_zone = 1;
1.1.1.3 misho 290: auth = 0;
291: continue;
292: }
1.1 misho 293: }
294:
295: for (rec = daemon->mxnames; rec; rec = rec->next)
1.1.1.4 misho 296: if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
1.1 misho 297: {
298: nxdomain = 0;
299:
1.1.1.4 misho 300: if (rc == 2 && qtype == T_MX)
1.1 misho 301: {
302: found = 1;
1.1.1.5 ! misho 303: log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
1.1 misho 304: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
305: NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
306: anscount++;
307: }
308: }
309:
310: for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
1.1.1.4 misho 311: if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
1.1 misho 312: {
313: nxdomain = 0;
314:
1.1.1.4 misho 315: if (rc == 2 && qtype == T_SRV)
1.1 misho 316: {
317: found = 1;
1.1.1.5 ! misho 318: log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
1.1 misho 319: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
320: NULL, T_SRV, C_IN, "sssd",
321: rec->priority, rec->weight, rec->srvport, rec->target))
322:
323: anscount++;
324: }
325:
326: /* unlink first SRV record found */
327: if (!move)
328: {
329: move = rec;
330: *up = rec->next;
331: }
332: else
333: up = &rec->next;
334: }
335: else
336: up = &rec->next;
337:
338: /* put first SRV record back at the end. */
339: if (move)
340: {
341: *up = move;
342: move->next = NULL;
343: }
344:
345: for (txt = daemon->rr; txt; txt = txt->next)
1.1.1.4 misho 346: if ((rc = hostname_issubdomain(name, txt->name)))
1.1 misho 347: {
348: nxdomain = 0;
1.1.1.4 misho 349: if (rc == 2 && txt->class == qtype)
1.1 misho 350: {
351: found = 1;
1.1.1.5 ! misho 352: log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
1.1 misho 353: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
354: NULL, txt->class, C_IN, "t", txt->len, txt->txt))
355: anscount++;
356: }
357: }
358:
359: for (txt = daemon->txt; txt; txt = txt->next)
1.1.1.4 misho 360: if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
1.1 misho 361: {
362: nxdomain = 0;
1.1.1.4 misho 363: if (rc == 2 && qtype == T_TXT)
1.1 misho 364: {
365: found = 1;
1.1.1.5 ! misho 366: log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
1.1 misho 367: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
368: NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
369: anscount++;
370: }
371: }
372:
373: for (na = daemon->naptr; na; na = na->next)
1.1.1.4 misho 374: if ((rc = hostname_issubdomain(name, na->name)))
1.1 misho 375: {
376: nxdomain = 0;
1.1.1.4 misho 377: if (rc == 2 && qtype == T_NAPTR)
1.1 misho 378: {
379: found = 1;
1.1.1.5 ! misho 380: log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
1.1 misho 381: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
382: NULL, T_NAPTR, C_IN, "sszzzd",
383: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
384: anscount++;
385: }
386: }
1.1.1.2 misho 387:
388: if (qtype == T_A)
389: flag = F_IPV4;
390:
391: if (qtype == T_AAAA)
392: flag = F_IPV6;
393:
1.1 misho 394: for (intr = daemon->int_names; intr; intr = intr->next)
1.1.1.4 misho 395: if ((rc = hostname_issubdomain(name, intr->name)))
1.1 misho 396: {
1.1.1.2 misho 397: struct addrlist *addrlist;
398:
1.1 misho 399: nxdomain = 0;
1.1.1.2 misho 400:
1.1.1.4 misho 401: if (rc == 2 && flag)
1.1.1.2 misho 402: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
403: if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
404: (local_query || filter_zone(zone, flag, &addrlist->addr)))
405: {
1.1.1.3 misho 406: if (addrlist->flags & ADDRLIST_REVONLY)
407: continue;
1.1.1.4 misho 408:
1.1.1.2 misho 409: found = 1;
1.1.1.5 ! misho 410: log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
1.1.1.2 misho 411: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
412: daemon->auth_ttl, NULL, qtype, C_IN,
413: qtype == T_A ? "4" : "6", &addrlist->addr))
414: anscount++;
415: }
416: }
1.1.1.5 ! misho 417:
! 418: if (!found && is_name_synthetic(flag, name, &addr) )
! 419: {
! 420: nxdomain = 0;
! 421:
! 422: log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
! 423: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 424: daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
! 425: anscount++;
! 426: }
1.1 misho 427:
428: if (!cut)
429: {
430: nxdomain = 0;
431:
432: if (qtype == T_SOA)
433: {
1.1.1.2 misho 434: auth = soa = 1; /* inhibits auth section */
1.1.1.5 ! misho 435: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
1.1 misho 436: }
437: else if (qtype == T_AXFR)
438: {
439: struct iname *peers;
440:
441: if (peer_addr->sa.sa_family == AF_INET)
442: peer_addr->in.sin_port = 0;
443: else
1.1.1.3 misho 444: {
445: peer_addr->in6.sin6_port = 0;
446: peer_addr->in6.sin6_scope_id = 0;
447: }
1.1 misho 448:
449: for (peers = daemon->auth_peers; peers; peers = peers->next)
450: if (sockaddr_isequal(peer_addr, &peers->addr))
451: break;
452:
1.1.1.4 misho 453: /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
454: if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
455: (daemon->auth_peers && !peers))
1.1 misho 456: {
457: if (peer_addr->sa.sa_family == AF_INET)
458: inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
459: else
460: inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
461:
462: my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
463: return 0;
464: }
465:
1.1.1.2 misho 466: auth = 1;
1.1 misho 467: soa = 1; /* inhibits auth section */
468: ns = 1; /* ensure we include NS records! */
469: axfr = 1;
470: axfroffset = nameoffset;
1.1.1.5 ! misho 471: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
1.1 misho 472: }
473: else if (qtype == T_NS)
474: {
1.1.1.2 misho 475: auth = 1;
1.1 misho 476: ns = 1; /* inhibits auth section */
1.1.1.5 ! misho 477: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
1.1 misho 478: }
479: }
480:
481: if (!option_bool(OPT_DHCP_FQDN) && cut)
482: {
483: *cut = 0; /* remove domain part */
484:
485: if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
486: {
487: if (crecp->flags & F_DHCP)
488: do
489: {
490: nxdomain = 0;
491: if ((crecp->flags & flag) &&
1.1.1.4 misho 492: (local_query || filter_zone(zone, flag, &(crecp->addr))))
1.1 misho 493: {
494: *cut = '.'; /* restore domain part */
1.1.1.5 ! misho 495: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
1.1 misho 496: *cut = 0; /* remove domain part */
497: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
498: daemon->auth_ttl, NULL, qtype, C_IN,
499: qtype == T_A ? "4" : "6", &crecp->addr))
500: anscount++;
501: }
502: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
503: }
504:
505: *cut = '.'; /* restore domain part */
506: }
507:
508: if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
509: {
510: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
511: do
512: {
513: nxdomain = 0;
1.1.1.4 misho 514: if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
1.1 misho 515: {
1.1.1.5 ! misho 516: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
1.1 misho 517: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
518: daemon->auth_ttl, NULL, qtype, C_IN,
519: qtype == T_A ? "4" : "6", &crecp->addr))
520: anscount++;
521: }
522: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
523: }
524:
1.1.1.4 misho 525: /* Only supply CNAME if no record for any type is known. */
526: if (nxdomain)
527: {
528: /* Check for possible wildcard match against *.domain
529: return length of match, to get longest.
530: Note that if return length of wildcard section, so
531: we match b.simon to _both_ *.simon and b.simon
532: but return a longer (better) match to b.simon.
533: */
534: for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
535: if (a->alias[0] == '*')
536: {
537: char *test = name;
538:
539: while ((test = strchr(test+1, '.')))
540: {
541: if (hostname_isequal(test, &(a->alias[1])))
542: {
543: if (strlen(test) > wclen && !cname_wildcard)
544: {
545: wclen = strlen(test);
546: candidate = a;
547: cname_wildcard = 1;
548: }
549: break;
550: }
551: }
552:
553: }
554: else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
555: {
556: /* Simple case, no wildcard */
557: wclen = strlen(a->alias);
558: candidate = a;
559: }
560:
561: if (candidate)
562: {
1.1.1.5 ! misho 563: log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
1.1.1.4 misho 564: strcpy(name, candidate->target);
565: if (!strchr(name, '.'))
566: {
567: strcat(name, ".");
568: strcat(name, zone->domain);
569: }
570: found = 1;
571: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
572: daemon->auth_ttl, &nameoffset,
573: T_CNAME, C_IN, "d", name))
574: anscount++;
575:
576: goto cname_restart;
577: }
578: else if (cache_find_non_terminal(name, now))
579: nxdomain = 0;
580:
1.1.1.5 ! misho 581: log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
1.1.1.4 misho 582: }
1.1 misho 583:
584: }
585:
586: /* Add auth section */
587: if (auth && zone)
588: {
589: char *authname;
590: int newoffset, offset = 0;
591:
592: if (!subnet)
593: authname = zone->domain;
594: else
595: {
596: /* handle NS and SOA for PTR records */
597:
598: authname = name;
599:
1.1.1.2 misho 600: if (!(subnet->flags & ADDRLIST_IPV6))
1.1 misho 601: {
1.1.1.4 misho 602: in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
1.1 misho 603: char *p = name;
604:
1.1.1.2 misho 605: if (subnet->prefixlen >= 24)
1.1.1.4 misho 606: p += sprintf(p, "%u.", a & 0xff);
1.1 misho 607: a = a >> 8;
1.1.1.2 misho 608: if (subnet->prefixlen >= 16 )
1.1.1.4 misho 609: p += sprintf(p, "%u.", a & 0xff);
1.1 misho 610: a = a >> 8;
1.1.1.5 ! misho 611: sprintf(p, "%u.in-addr.arpa", a & 0xff);
1.1 misho 612:
613: }
614: else
615: {
616: char *p = name;
617: int i;
618:
619: for (i = subnet->prefixlen-1; i >= 0; i -= 4)
620: {
1.1.1.4 misho 621: int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
1.1 misho 622: p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
623: }
1.1.1.5 ! misho 624: sprintf(p, "ip6.arpa");
1.1 misho 625:
626: }
627: }
628:
629: /* handle NS and SOA in auth section or for explicit queries */
630: newoffset = ansp - (unsigned char *)header;
631: if (((anscount == 0 && !ns) || soa) &&
632: add_resource_record(header, limit, &trunc, 0, &ansp,
633: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
634: authname, daemon->authserver, daemon->hostmaster,
635: daemon->soa_sn, daemon->soa_refresh,
636: daemon->soa_retry, daemon->soa_expiry,
637: daemon->auth_ttl))
638: {
639: offset = newoffset;
640: if (soa)
641: anscount++;
642: else
643: authcount++;
644: }
645:
646: if (anscount != 0 || ns)
647: {
648: struct name_list *secondary;
649:
1.1.1.4 misho 650: /* Only include the machine running dnsmasq if it's acting as an auth server */
651: if (daemon->authinterface)
652: {
653: newoffset = ansp - (unsigned char *)header;
654: if (add_resource_record(header, limit, &trunc, -offset, &ansp,
655: daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
656: {
657: if (offset == 0)
658: offset = newoffset;
659: if (ns)
660: anscount++;
661: else
662: authcount++;
663: }
1.1 misho 664: }
665:
666: if (!subnet)
667: for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
668: if (add_resource_record(header, limit, &trunc, offset, &ansp,
669: daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
670: {
671: if (ns)
672: anscount++;
673: else
674: authcount++;
675: }
676: }
677:
678: if (axfr)
679: {
680: for (rec = daemon->mxnames; rec; rec = rec->next)
681: if (in_zone(zone, rec->name, &cut))
682: {
683: if (cut)
684: *cut = 0;
685:
686: if (rec->issrv)
687: {
688: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
689: NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
690: rec->priority, rec->weight, rec->srvport, rec->target))
691:
692: anscount++;
693: }
694: else
695: {
696: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
697: NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
698: anscount++;
699: }
700:
701: /* restore config data */
702: if (cut)
703: *cut = '.';
704: }
705:
706: for (txt = daemon->rr; txt; txt = txt->next)
707: if (in_zone(zone, txt->name, &cut))
708: {
709: if (cut)
710: *cut = 0;
711:
712: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
713: NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
714: anscount++;
715:
716: /* restore config data */
717: if (cut)
718: *cut = '.';
719: }
720:
721: for (txt = daemon->txt; txt; txt = txt->next)
722: if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
723: {
724: if (cut)
725: *cut = 0;
726:
727: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
728: NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
729: anscount++;
730:
731: /* restore config data */
732: if (cut)
733: *cut = '.';
734: }
735:
736: for (na = daemon->naptr; na; na = na->next)
737: if (in_zone(zone, na->name, &cut))
738: {
739: if (cut)
740: *cut = 0;
741:
742: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
743: NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
744: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
745: anscount++;
746:
747: /* restore config data */
748: if (cut)
749: *cut = '.';
750: }
751:
752: for (intr = daemon->int_names; intr; intr = intr->next)
1.1.1.2 misho 753: if (in_zone(zone, intr->name, &cut))
1.1 misho 754: {
1.1.1.2 misho 755: struct addrlist *addrlist;
756:
1.1 misho 757: if (cut)
758: *cut = 0;
759:
1.1.1.2 misho 760: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
761: if (!(addrlist->flags & ADDRLIST_IPV6) &&
762: (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
763: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
764: daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
765: anscount++;
766:
767: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
768: if ((addrlist->flags & ADDRLIST_IPV6) &&
769: (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
770: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
771: daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
772: anscount++;
1.1 misho 773:
774: /* restore config data */
775: if (cut)
776: *cut = '.';
777: }
1.1.1.2 misho 778:
1.1 misho 779: for (a = daemon->cnames; a; a = a->next)
780: if (in_zone(zone, a->alias, &cut))
781: {
782: strcpy(name, a->target);
783: if (!strchr(name, '.'))
784: {
785: strcat(name, ".");
786: strcat(name, zone->domain);
787: }
788:
789: if (cut)
790: *cut = 0;
791:
792: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
793: daemon->auth_ttl, NULL,
794: T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
795: anscount++;
796: }
797:
798: cache_enumerate(1);
799: while ((crecp = cache_enumerate(0)))
800: {
801: if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
802: !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
803: (crecp->flags & F_FORWARD))
804: {
805: if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
806: {
807: char *cache_name = cache_get_name(crecp);
1.1.1.2 misho 808: if (!strchr(cache_name, '.') &&
1.1.1.4 misho 809: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
810: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
811: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
812: (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
813: anscount++;
1.1 misho 814: }
815:
816: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
817: {
818: strcpy(name, cache_get_name(crecp));
1.1.1.2 misho 819: if (in_zone(zone, name, &cut) &&
1.1.1.4 misho 820: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
1.1 misho 821: {
1.1.1.4 misho 822: if (cut)
823: *cut = 0;
824:
825: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
826: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
827: (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
828: anscount++;
1.1 misho 829: }
830: }
831: }
832: }
833:
834: /* repeat SOA as last record */
835: if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
836: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
837: daemon->authserver, daemon->hostmaster,
838: daemon->soa_sn, daemon->soa_refresh,
839: daemon->soa_retry, daemon->soa_expiry,
840: daemon->auth_ttl))
841: anscount++;
842:
843: }
844:
845: }
846:
847: /* done all questions, set up header and return length of result */
848: /* clear authoritative and truncated flags, set QR flag */
849: header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1.1.1.2 misho 850:
851: if (local_query)
852: {
853: /* set RA flag */
854: header->hb4 |= HB4_RA;
855: }
856: else
857: {
858: /* clear RA flag */
859: header->hb4 &= ~HB4_RA;
860: }
1.1 misho 861:
1.1.1.4 misho 862: /* data is never DNSSEC signed. */
863: header->hb4 &= ~HB4_AD;
864:
865: /* authoritative */
1.1 misho 866: if (auth)
867: header->hb3 |= HB3_AA;
868:
869: /* truncation */
870: if (trunc)
871: header->hb3 |= HB3_TC;
872:
1.1.1.2 misho 873: if ((auth || local_query) && nxdomain)
1.1 misho 874: SET_RCODE(header, NXDOMAIN);
875: else
876: SET_RCODE(header, NOERROR); /* no error */
1.1.1.5 ! misho 877:
1.1 misho 878: header->ancount = htons(anscount);
879: header->nscount = htons(authcount);
880: header->arcount = htons(0);
1.1.1.3 misho 881:
1.1.1.5 ! misho 882: if (!local_query && out_of_zone)
! 883: {
! 884: SET_RCODE(header, REFUSED);
! 885: header->ancount = htons(0);
! 886: header->nscount = htons(0);
! 887: addr.log.rcode = REFUSED;
! 888: addr.log.ede = EDE_NOT_AUTH;
! 889: log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
! 890: return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
! 891: }
! 892:
1.1.1.3 misho 893: /* Advertise our packet size limit in our reply */
894: if (have_pseudoheader)
895: return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
896:
1.1 misho 897: return ansp - (unsigned char *)header;
898: }
899:
900: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>