Annotation of embedaddon/dnsmasq/src/auth.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 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.2 misho 108: int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 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;
149: continue;
150: }
151:
1.1.1.3 misho 152: if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
153: (flag = in_arpa_name_2_addr(name, &addr)) &&
154: !local_query)
155: {
156: for (zone = daemon->auth_zones; zone; zone = zone->next)
157: if ((subnet = find_subnet(zone, flag, &addr)))
158: break;
159:
160: if (!zone)
1.1 misho 161: {
1.1.1.3 misho 162: auth = 0;
163: continue;
1.1.1.2 misho 164: }
1.1.1.3 misho 165: else if (qtype == T_SOA)
166: soa = 1, found = 1;
167: else if (qtype == T_NS)
168: ns = 1, found = 1;
169: }
1.1 misho 170:
1.1.1.3 misho 171: if (qtype == T_PTR && flag)
172: {
1.1.1.2 misho 173: intr = NULL;
174:
175: if (flag == F_IPV4)
176: for (intr = daemon->int_names; intr; intr = intr->next)
177: {
178: struct addrlist *addrlist;
179:
180: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1.1.1.4 ! misho 181: if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
1.1.1.2 misho 182: break;
183:
184: if (addrlist)
185: break;
186: else
187: while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
188: intr = intr->next;
189: }
190: else if (flag == F_IPV6)
191: for (intr = daemon->int_names; intr; intr = intr->next)
192: {
193: struct addrlist *addrlist;
194:
195: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1.1.1.4 ! misho 196: if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
1.1.1.2 misho 197: break;
198:
199: if (addrlist)
200: break;
201: else
202: while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
203: intr = intr->next;
204: }
205:
206: if (intr)
207: {
1.1.1.3 misho 208: if (local_query || in_zone(zone, intr->name, NULL))
1.1.1.2 misho 209: {
210: found = 1;
211: log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
212: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
213: daemon->auth_ttl, NULL,
214: T_PTR, C_IN, "d", intr->name))
215: anscount++;
1.1 misho 216: }
217: }
1.1.1.2 misho 218:
1.1 misho 219: if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
220: do {
221: strcpy(name, cache_get_name(crecp));
222:
223: if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
224: {
225: char *p = strchr(name, '.');
226: if (p)
227: *p = 0; /* must be bare name */
228:
229: /* add external domain */
1.1.1.3 misho 230: if (zone)
231: {
232: strcat(name, ".");
233: strcat(name, zone->domain);
234: }
1.1 misho 235: log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
236: found = 1;
237: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
238: daemon->auth_ttl, NULL,
239: T_PTR, C_IN, "d", name))
240: anscount++;
241: }
1.1.1.3 misho 242: else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
1.1 misho 243: {
244: log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
245: found = 1;
246: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
247: daemon->auth_ttl, NULL,
248: T_PTR, C_IN, "d", name))
249: anscount++;
250: }
251: else
252: continue;
253:
254: } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
255:
1.1.1.2 misho 256: if (found)
257: nxdomain = 0;
258: else
259: log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
1.1 misho 260:
261: continue;
262: }
263:
264: cname_restart:
1.1.1.3 misho 265: if (found)
266: /* NS and SOA .arpa requests have set found above. */
267: cut = NULL;
268: else
1.1 misho 269: {
1.1.1.3 misho 270: for (zone = daemon->auth_zones; zone; zone = zone->next)
271: if (in_zone(zone, name, &cut))
272: break;
273:
274: if (!zone)
275: {
276: auth = 0;
277: continue;
278: }
1.1 misho 279: }
280:
281: for (rec = daemon->mxnames; rec; rec = rec->next)
1.1.1.4 ! misho 282: if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
1.1 misho 283: {
284: nxdomain = 0;
285:
1.1.1.4 ! misho 286: if (rc == 2 && qtype == T_MX)
1.1 misho 287: {
288: found = 1;
289: log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
290: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
291: NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
292: anscount++;
293: }
294: }
295:
296: for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
1.1.1.4 ! misho 297: if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
1.1 misho 298: {
299: nxdomain = 0;
300:
1.1.1.4 ! misho 301: if (rc == 2 && qtype == T_SRV)
1.1 misho 302: {
303: found = 1;
304: log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
305: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
306: NULL, T_SRV, C_IN, "sssd",
307: rec->priority, rec->weight, rec->srvport, rec->target))
308:
309: anscount++;
310: }
311:
312: /* unlink first SRV record found */
313: if (!move)
314: {
315: move = rec;
316: *up = rec->next;
317: }
318: else
319: up = &rec->next;
320: }
321: else
322: up = &rec->next;
323:
324: /* put first SRV record back at the end. */
325: if (move)
326: {
327: *up = move;
328: move->next = NULL;
329: }
330:
331: for (txt = daemon->rr; txt; txt = txt->next)
1.1.1.4 ! misho 332: if ((rc = hostname_issubdomain(name, txt->name)))
1.1 misho 333: {
334: nxdomain = 0;
1.1.1.4 ! misho 335: if (rc == 2 && txt->class == qtype)
1.1 misho 336: {
337: found = 1;
1.1.1.4 ! misho 338: log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
1.1 misho 339: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
340: NULL, txt->class, C_IN, "t", txt->len, txt->txt))
341: anscount++;
342: }
343: }
344:
345: for (txt = daemon->txt; txt; txt = txt->next)
1.1.1.4 ! misho 346: if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
1.1 misho 347: {
348: nxdomain = 0;
1.1.1.4 ! misho 349: if (rc == 2 && qtype == T_TXT)
1.1 misho 350: {
351: found = 1;
352: log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
353: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
354: NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
355: anscount++;
356: }
357: }
358:
359: for (na = daemon->naptr; na; na = na->next)
1.1.1.4 ! misho 360: if ((rc = hostname_issubdomain(name, na->name)))
1.1 misho 361: {
362: nxdomain = 0;
1.1.1.4 ! misho 363: if (rc == 2 && qtype == T_NAPTR)
1.1 misho 364: {
365: found = 1;
366: log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
367: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
368: NULL, T_NAPTR, C_IN, "sszzzd",
369: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
370: anscount++;
371: }
372: }
1.1.1.2 misho 373:
374: if (qtype == T_A)
375: flag = F_IPV4;
376:
377: if (qtype == T_AAAA)
378: flag = F_IPV6;
379:
1.1 misho 380: for (intr = daemon->int_names; intr; intr = intr->next)
1.1.1.4 ! misho 381: if ((rc = hostname_issubdomain(name, intr->name)))
1.1 misho 382: {
1.1.1.2 misho 383: struct addrlist *addrlist;
384:
1.1 misho 385: nxdomain = 0;
1.1.1.2 misho 386:
1.1.1.4 ! misho 387: if (rc == 2 && flag)
1.1.1.2 misho 388: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
389: if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
390: (local_query || filter_zone(zone, flag, &addrlist->addr)))
391: {
1.1.1.3 misho 392: if (addrlist->flags & ADDRLIST_REVONLY)
393: continue;
1.1.1.4 ! misho 394:
1.1.1.2 misho 395: found = 1;
396: log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
397: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
398: daemon->auth_ttl, NULL, qtype, C_IN,
399: qtype == T_A ? "4" : "6", &addrlist->addr))
400: anscount++;
401: }
402: }
1.1 misho 403:
404: if (!cut)
405: {
406: nxdomain = 0;
407:
408: if (qtype == T_SOA)
409: {
1.1.1.2 misho 410: auth = soa = 1; /* inhibits auth section */
1.1 misho 411: found = 1;
412: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
413: }
414: else if (qtype == T_AXFR)
415: {
416: struct iname *peers;
417:
418: if (peer_addr->sa.sa_family == AF_INET)
419: peer_addr->in.sin_port = 0;
420: else
1.1.1.3 misho 421: {
422: peer_addr->in6.sin6_port = 0;
423: peer_addr->in6.sin6_scope_id = 0;
424: }
1.1 misho 425:
426: for (peers = daemon->auth_peers; peers; peers = peers->next)
427: if (sockaddr_isequal(peer_addr, &peers->addr))
428: break;
429:
1.1.1.4 ! misho 430: /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
! 431: if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
! 432: (daemon->auth_peers && !peers))
1.1 misho 433: {
434: if (peer_addr->sa.sa_family == AF_INET)
435: inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
436: else
437: inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
438:
439: my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
440: return 0;
441: }
442:
1.1.1.2 misho 443: auth = 1;
1.1 misho 444: soa = 1; /* inhibits auth section */
445: ns = 1; /* ensure we include NS records! */
446: axfr = 1;
447: found = 1;
448: axfroffset = nameoffset;
449: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
450: }
451: else if (qtype == T_NS)
452: {
1.1.1.2 misho 453: auth = 1;
1.1 misho 454: ns = 1; /* inhibits auth section */
455: found = 1;
456: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
457: }
458: }
459:
460: if (!option_bool(OPT_DHCP_FQDN) && cut)
461: {
462: *cut = 0; /* remove domain part */
463:
464: if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
465: {
466: if (crecp->flags & F_DHCP)
467: do
468: {
469: nxdomain = 0;
470: if ((crecp->flags & flag) &&
1.1.1.4 ! misho 471: (local_query || filter_zone(zone, flag, &(crecp->addr))))
1.1 misho 472: {
473: *cut = '.'; /* restore domain part */
1.1.1.4 ! misho 474: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
1.1 misho 475: *cut = 0; /* remove domain part */
476: found = 1;
477: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
478: daemon->auth_ttl, NULL, qtype, C_IN,
479: qtype == T_A ? "4" : "6", &crecp->addr))
480: anscount++;
481: }
482: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
483: }
484:
485: *cut = '.'; /* restore domain part */
486: }
487:
488: if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
489: {
490: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
491: do
492: {
493: nxdomain = 0;
1.1.1.4 ! misho 494: if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
1.1 misho 495: {
1.1.1.4 ! misho 496: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
1.1 misho 497: found = 1;
498: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
499: daemon->auth_ttl, NULL, qtype, C_IN,
500: qtype == T_A ? "4" : "6", &crecp->addr))
501: anscount++;
502: }
503: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
504: }
505:
1.1.1.4 ! misho 506: /* Only supply CNAME if no record for any type is known. */
! 507: if (nxdomain)
! 508: {
! 509: /* Check for possible wildcard match against *.domain
! 510: return length of match, to get longest.
! 511: Note that if return length of wildcard section, so
! 512: we match b.simon to _both_ *.simon and b.simon
! 513: but return a longer (better) match to b.simon.
! 514: */
! 515: for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
! 516: if (a->alias[0] == '*')
! 517: {
! 518: char *test = name;
! 519:
! 520: while ((test = strchr(test+1, '.')))
! 521: {
! 522: if (hostname_isequal(test, &(a->alias[1])))
! 523: {
! 524: if (strlen(test) > wclen && !cname_wildcard)
! 525: {
! 526: wclen = strlen(test);
! 527: candidate = a;
! 528: cname_wildcard = 1;
! 529: }
! 530: break;
! 531: }
! 532: }
! 533:
! 534: }
! 535: else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
! 536: {
! 537: /* Simple case, no wildcard */
! 538: wclen = strlen(a->alias);
! 539: candidate = a;
! 540: }
! 541:
! 542: if (candidate)
! 543: {
! 544: log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
! 545: strcpy(name, candidate->target);
! 546: if (!strchr(name, '.'))
! 547: {
! 548: strcat(name, ".");
! 549: strcat(name, zone->domain);
! 550: }
! 551: found = 1;
! 552: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 553: daemon->auth_ttl, &nameoffset,
! 554: T_CNAME, C_IN, "d", name))
! 555: anscount++;
! 556:
! 557: goto cname_restart;
! 558: }
! 559: else if (cache_find_non_terminal(name, now))
! 560: nxdomain = 0;
! 561:
! 562: log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
! 563: }
1.1 misho 564:
565: }
566:
567: /* Add auth section */
568: if (auth && zone)
569: {
570: char *authname;
571: int newoffset, offset = 0;
572:
573: if (!subnet)
574: authname = zone->domain;
575: else
576: {
577: /* handle NS and SOA for PTR records */
578:
579: authname = name;
580:
1.1.1.2 misho 581: if (!(subnet->flags & ADDRLIST_IPV6))
1.1 misho 582: {
1.1.1.4 ! misho 583: in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
1.1 misho 584: char *p = name;
585:
1.1.1.2 misho 586: if (subnet->prefixlen >= 24)
1.1.1.4 ! misho 587: p += sprintf(p, "%u.", a & 0xff);
1.1 misho 588: a = a >> 8;
1.1.1.2 misho 589: if (subnet->prefixlen >= 16 )
1.1.1.4 ! misho 590: p += sprintf(p, "%u.", a & 0xff);
1.1 misho 591: a = a >> 8;
1.1.1.4 ! misho 592: p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
1.1 misho 593:
594: }
595: else
596: {
597: char *p = name;
598: int i;
599:
600: for (i = subnet->prefixlen-1; i >= 0; i -= 4)
601: {
1.1.1.4 ! misho 602: int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
1.1 misho 603: p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
604: }
605: p += sprintf(p, "ip6.arpa");
606:
607: }
608: }
609:
610: /* handle NS and SOA in auth section or for explicit queries */
611: newoffset = ansp - (unsigned char *)header;
612: if (((anscount == 0 && !ns) || soa) &&
613: add_resource_record(header, limit, &trunc, 0, &ansp,
614: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
615: authname, daemon->authserver, daemon->hostmaster,
616: daemon->soa_sn, daemon->soa_refresh,
617: daemon->soa_retry, daemon->soa_expiry,
618: daemon->auth_ttl))
619: {
620: offset = newoffset;
621: if (soa)
622: anscount++;
623: else
624: authcount++;
625: }
626:
627: if (anscount != 0 || ns)
628: {
629: struct name_list *secondary;
630:
1.1.1.4 ! misho 631: /* Only include the machine running dnsmasq if it's acting as an auth server */
! 632: if (daemon->authinterface)
! 633: {
! 634: newoffset = ansp - (unsigned char *)header;
! 635: if (add_resource_record(header, limit, &trunc, -offset, &ansp,
! 636: daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
! 637: {
! 638: if (offset == 0)
! 639: offset = newoffset;
! 640: if (ns)
! 641: anscount++;
! 642: else
! 643: authcount++;
! 644: }
1.1 misho 645: }
646:
647: if (!subnet)
648: for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
649: if (add_resource_record(header, limit, &trunc, offset, &ansp,
650: daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
651: {
652: if (ns)
653: anscount++;
654: else
655: authcount++;
656: }
657: }
658:
659: if (axfr)
660: {
661: for (rec = daemon->mxnames; rec; rec = rec->next)
662: if (in_zone(zone, rec->name, &cut))
663: {
664: if (cut)
665: *cut = 0;
666:
667: if (rec->issrv)
668: {
669: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
670: NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
671: rec->priority, rec->weight, rec->srvport, rec->target))
672:
673: anscount++;
674: }
675: else
676: {
677: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
678: NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
679: anscount++;
680: }
681:
682: /* restore config data */
683: if (cut)
684: *cut = '.';
685: }
686:
687: for (txt = daemon->rr; txt; txt = txt->next)
688: if (in_zone(zone, txt->name, &cut))
689: {
690: if (cut)
691: *cut = 0;
692:
693: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
694: NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
695: anscount++;
696:
697: /* restore config data */
698: if (cut)
699: *cut = '.';
700: }
701:
702: for (txt = daemon->txt; txt; txt = txt->next)
703: if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
704: {
705: if (cut)
706: *cut = 0;
707:
708: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
709: NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
710: anscount++;
711:
712: /* restore config data */
713: if (cut)
714: *cut = '.';
715: }
716:
717: for (na = daemon->naptr; na; na = na->next)
718: if (in_zone(zone, na->name, &cut))
719: {
720: if (cut)
721: *cut = 0;
722:
723: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
724: NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
725: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
726: anscount++;
727:
728: /* restore config data */
729: if (cut)
730: *cut = '.';
731: }
732:
733: for (intr = daemon->int_names; intr; intr = intr->next)
1.1.1.2 misho 734: if (in_zone(zone, intr->name, &cut))
1.1 misho 735: {
1.1.1.2 misho 736: struct addrlist *addrlist;
737:
1.1 misho 738: if (cut)
739: *cut = 0;
740:
1.1.1.2 misho 741: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
742: if (!(addrlist->flags & ADDRLIST_IPV6) &&
743: (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
744: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
745: daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
746: anscount++;
747:
748: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
749: if ((addrlist->flags & ADDRLIST_IPV6) &&
750: (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
751: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
752: daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
753: anscount++;
1.1 misho 754:
755: /* restore config data */
756: if (cut)
757: *cut = '.';
758: }
1.1.1.2 misho 759:
1.1 misho 760: for (a = daemon->cnames; a; a = a->next)
761: if (in_zone(zone, a->alias, &cut))
762: {
763: strcpy(name, a->target);
764: if (!strchr(name, '.'))
765: {
766: strcat(name, ".");
767: strcat(name, zone->domain);
768: }
769:
770: if (cut)
771: *cut = 0;
772:
773: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
774: daemon->auth_ttl, NULL,
775: T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
776: anscount++;
777: }
778:
779: cache_enumerate(1);
780: while ((crecp = cache_enumerate(0)))
781: {
782: if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
783: !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
784: (crecp->flags & F_FORWARD))
785: {
786: if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
787: {
788: char *cache_name = cache_get_name(crecp);
1.1.1.2 misho 789: if (!strchr(cache_name, '.') &&
1.1.1.4 ! misho 790: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
! 791: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
! 792: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
! 793: (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
! 794: anscount++;
1.1 misho 795: }
796:
797: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
798: {
799: strcpy(name, cache_get_name(crecp));
1.1.1.2 misho 800: if (in_zone(zone, name, &cut) &&
1.1.1.4 ! misho 801: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
1.1 misho 802: {
1.1.1.4 ! misho 803: if (cut)
! 804: *cut = 0;
! 805:
! 806: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
! 807: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
! 808: (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
! 809: anscount++;
1.1 misho 810: }
811: }
812: }
813: }
814:
815: /* repeat SOA as last record */
816: if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
817: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
818: daemon->authserver, daemon->hostmaster,
819: daemon->soa_sn, daemon->soa_refresh,
820: daemon->soa_retry, daemon->soa_expiry,
821: daemon->auth_ttl))
822: anscount++;
823:
824: }
825:
826: }
827:
828: /* done all questions, set up header and return length of result */
829: /* clear authoritative and truncated flags, set QR flag */
830: header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1.1.1.2 misho 831:
832: if (local_query)
833: {
834: /* set RA flag */
835: header->hb4 |= HB4_RA;
836: }
837: else
838: {
839: /* clear RA flag */
840: header->hb4 &= ~HB4_RA;
841: }
1.1 misho 842:
1.1.1.4 ! misho 843: /* data is never DNSSEC signed. */
! 844: header->hb4 &= ~HB4_AD;
! 845:
! 846: /* authoritative */
1.1 misho 847: if (auth)
848: header->hb3 |= HB3_AA;
849:
850: /* truncation */
851: if (trunc)
852: header->hb3 |= HB3_TC;
853:
1.1.1.2 misho 854: if ((auth || local_query) && nxdomain)
1.1 misho 855: SET_RCODE(header, NXDOMAIN);
856: else
857: SET_RCODE(header, NOERROR); /* no error */
858: header->ancount = htons(anscount);
859: header->nscount = htons(authcount);
860: header->arcount = htons(0);
1.1.1.3 misho 861:
862: /* Advertise our packet size limit in our reply */
863: if (have_pseudoheader)
864: return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
865:
1.1 misho 866: return ansp - (unsigned char *)header;
867: }
868:
869: #endif
870:
871:
872:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>