1 /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
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.
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.
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/>.
21 static struct addrlist
*find_subnet(struct auth_zone
*zone
, int flag
, struct all_addr
*addr_u
)
23 struct addrlist
*subnet
;
25 for (subnet
= zone
->subnet
; subnet
; subnet
= subnet
->next
)
27 if (!(subnet
->flags
& ADDRLIST_IPV6
))
29 struct in_addr netmask
, addr
= addr_u
->addr
.addr4
;
34 netmask
.s_addr
= htonl(~(in_addr_t
)0 << (32 - subnet
->prefixlen
));
36 if (is_same_net(addr
, subnet
->addr
.addr
.addr4
, netmask
))
40 else if (is_same_net6(&(addr_u
->addr
.addr6
), &subnet
->addr
.addr
.addr6
, subnet
->prefixlen
))
48 static int filter_zone(struct auth_zone
*zone
, int flag
, struct all_addr
*addr_u
)
50 /* No zones specified, no filter */
54 return find_subnet(zone
, flag
, addr_u
) != NULL
;
57 int in_zone(struct auth_zone
*zone
, char *name
, char **cut
)
59 size_t namelen
= strlen(name
);
60 size_t domainlen
= strlen(zone
->domain
);
65 if (namelen
>= domainlen
&&
66 hostname_isequal(zone
->domain
, &name
[namelen
- domainlen
]))
69 if (namelen
== domainlen
)
72 if (name
[namelen
- domainlen
- 1] == '.')
75 *cut
= &name
[namelen
- domainlen
- 1];
84 size_t answer_auth(struct dns_header
*header
, char *limit
, size_t qlen
, time_t now
, union mysockaddr
*peer_addr
,
85 int local_query
, int do_bit
, int have_pseudoheader
)
87 char *name
= daemon
->namebuff
;
88 unsigned char *p
, *ansp
;
90 int nameoffset
, axfroffset
= 0;
91 int q
, anscount
= 0, authcount
= 0;
93 int auth
= !local_query
, trunc
= 0, nxdomain
= 1, soa
= 0, ns
= 0, axfr
= 0;
94 struct auth_zone
*zone
= NULL
;
95 struct addrlist
*subnet
= NULL
;
97 struct mx_srv_record
*rec
, *move
, **up
;
98 struct txt_record
*txt
;
99 struct interface_name
*intr
;
101 struct all_addr addr
;
104 if (ntohs(header
->qdcount
) == 0 || OPCODE(header
) != QUERY
)
107 /* determine end of question section (we put answers there) */
108 if (!(ansp
= skip_questions(header
, qlen
)))
109 return 0; /* bad packet */
111 /* now process each question, answers go in RRs after the question */
112 p
= (unsigned char *)(header
+1);
114 for (q
= ntohs(header
->qdcount
); q
!= 0; q
--)
116 unsigned short flag
= 0;
119 /* save pointer to name for copying into answers */
120 nameoffset
= p
- (unsigned char *)header
;
122 /* now extract name as .-concatenated string into name */
123 if (!extract_name(header
, qlen
, &p
, name
, 1, 4))
124 return 0; /* bad packet */
135 if ((qtype
== T_PTR
|| qtype
== T_SOA
|| qtype
== T_NS
) &&
136 (flag
= in_arpa_name_2_addr(name
, &addr
)) &&
139 for (zone
= daemon
->auth_zones
; zone
; zone
= zone
->next
)
140 if ((subnet
= find_subnet(zone
, flag
, &addr
)))
148 else if (qtype
== T_SOA
)
150 else if (qtype
== T_NS
)
154 if (qtype
== T_PTR
&& flag
)
159 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
161 struct addrlist
*addrlist
;
163 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
164 if (!(addrlist
->flags
& ADDRLIST_IPV6
) && addr
.addr
.addr4
.s_addr
== addrlist
->addr
.addr
.addr4
.s_addr
)
170 while (intr
->next
&& strcmp(intr
->intr
, intr
->next
->intr
) == 0)
174 else if (flag
== F_IPV6
)
175 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
177 struct addrlist
*addrlist
;
179 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
180 if ((addrlist
->flags
& ADDRLIST_IPV6
) && IN6_ARE_ADDR_EQUAL(&addr
.addr
.addr6
, &addrlist
->addr
.addr
.addr6
))
186 while (intr
->next
&& strcmp(intr
->intr
, intr
->next
->intr
) == 0)
193 if (local_query
|| in_zone(zone
, intr
->name
, NULL
))
196 log_query(flag
| F_REVERSE
| F_CONFIG
, intr
->name
, &addr
, NULL
);
197 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
198 daemon
->auth_ttl
, NULL
,
199 T_PTR
, C_IN
, "d", intr
->name
))
204 if ((crecp
= cache_find_by_addr(NULL
, &addr
, now
, flag
)))
206 strcpy(name
, cache_get_name(crecp
));
208 if (crecp
->flags
& F_DHCP
&& !option_bool(OPT_DHCP_FQDN
))
210 char *p
= strchr(name
, '.');
212 *p
= 0; /* must be bare name */
214 /* add external domain */
218 strcat(name
, zone
->domain
);
220 log_query(flag
| F_DHCP
| F_REVERSE
, name
, &addr
, record_source(crecp
->uid
));
222 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
223 daemon
->auth_ttl
, NULL
,
224 T_PTR
, C_IN
, "d", name
))
227 else if (crecp
->flags
& (F_DHCP
| F_HOSTS
) && (local_query
|| in_zone(zone
, name
, NULL
)))
229 log_query(crecp
->flags
& ~F_FORWARD
, name
, &addr
, record_source(crecp
->uid
));
231 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
232 daemon
->auth_ttl
, NULL
,
233 T_PTR
, C_IN
, "d", name
))
239 } while ((crecp
= cache_find_by_addr(crecp
, &addr
, now
, flag
)));
244 log_query(flag
| F_NEG
| F_NXDOMAIN
| F_REVERSE
| (auth
? F_AUTH
: 0), NULL
, &addr
, NULL
);
251 /* NS and SOA .arpa requests have set found above. */
255 for (zone
= daemon
->auth_zones
; zone
; zone
= zone
->next
)
256 if (in_zone(zone
, name
, &cut
))
266 for (rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
267 if (!rec
->issrv
&& hostname_isequal(name
, rec
->name
))
274 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<MX>");
275 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
276 NULL
, T_MX
, C_IN
, "sd", rec
->weight
, rec
->target
))
281 for (move
= NULL
, up
= &daemon
->mxnames
, rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
282 if (rec
->issrv
&& hostname_isequal(name
, rec
->name
))
289 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<SRV>");
290 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
291 NULL
, T_SRV
, C_IN
, "sssd",
292 rec
->priority
, rec
->weight
, rec
->srvport
, rec
->target
))
297 /* unlink first SRV record found */
309 /* put first SRV record back at the end. */
316 for (txt
= daemon
->rr
; txt
; txt
= txt
->next
)
317 if (hostname_isequal(name
, txt
->name
))
320 if (txt
->class == qtype
)
323 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<RR>");
324 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
325 NULL
, txt
->class, C_IN
, "t", txt
->len
, txt
->txt
))
330 for (txt
= daemon
->txt
; txt
; txt
= txt
->next
)
331 if (txt
->class == C_IN
&& hostname_isequal(name
, txt
->name
))
337 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<TXT>");
338 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
339 NULL
, T_TXT
, C_IN
, "t", txt
->len
, txt
->txt
))
344 for (na
= daemon
->naptr
; na
; na
= na
->next
)
345 if (hostname_isequal(name
, na
->name
))
348 if (qtype
== T_NAPTR
)
351 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<NAPTR>");
352 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
353 NULL
, T_NAPTR
, C_IN
, "sszzzd",
354 na
->order
, na
->pref
, na
->flags
, na
->services
, na
->regexp
, na
->replace
))
367 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
368 if (hostname_isequal(name
, intr
->name
))
370 struct addrlist
*addrlist
;
375 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
376 if (((addrlist
->flags
& ADDRLIST_IPV6
) ? T_AAAA
: T_A
) == qtype
&&
377 (local_query
|| filter_zone(zone
, flag
, &addrlist
->addr
)))
380 if (addrlist
->flags
& ADDRLIST_REVONLY
)
384 log_query(F_FORWARD
| F_CONFIG
| flag
, name
, &addrlist
->addr
, NULL
);
385 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
386 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
387 qtype
== T_A
? "4" : "6", &addrlist
->addr
))
392 for (a
= daemon
->cnames
; a
; a
= a
->next
)
393 if (hostname_isequal(name
, a
->alias
) )
395 log_query(F_CONFIG
| F_CNAME
, name
, NULL
, NULL
);
396 strcpy(name
, a
->target
);
397 if (!strchr(name
, '.'))
400 strcat(name
, zone
->domain
);
403 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
404 daemon
->auth_ttl
, &nameoffset
,
405 T_CNAME
, C_IN
, "d", name
))
417 auth
= soa
= 1; /* inhibits auth section */
419 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<SOA>");
421 else if (qtype
== T_AXFR
)
425 if (peer_addr
->sa
.sa_family
== AF_INET
)
426 peer_addr
->in
.sin_port
= 0;
430 peer_addr
->in6
.sin6_port
= 0;
431 peer_addr
->in6
.sin6_scope_id
= 0;
435 for (peers
= daemon
->auth_peers
; peers
; peers
= peers
->next
)
436 if (sockaddr_isequal(peer_addr
, &peers
->addr
))
439 /* Refuse all AXFR unless --auth-sec-servers is set */
440 if ((!peers
&& daemon
->auth_peers
) || !daemon
->secondary_forward_server
)
442 if (peer_addr
->sa
.sa_family
== AF_INET
)
443 inet_ntop(AF_INET
, &peer_addr
->in
.sin_addr
, daemon
->addrbuff
, ADDRSTRLEN
);
446 inet_ntop(AF_INET6
, &peer_addr
->in6
.sin6_addr
, daemon
->addrbuff
, ADDRSTRLEN
);
449 my_syslog(LOG_WARNING
, _("ignoring zone transfer request from %s"), daemon
->addrbuff
);
454 soa
= 1; /* inhibits auth section */
455 ns
= 1; /* ensure we include NS records! */
458 axfroffset
= nameoffset
;
459 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<AXFR>");
461 else if (qtype
== T_NS
)
464 ns
= 1; /* inhibits auth section */
466 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<NS>");
470 if (!option_bool(OPT_DHCP_FQDN
) && cut
)
472 *cut
= 0; /* remove domain part */
474 if (!strchr(name
, '.') && (crecp
= cache_find_by_name(NULL
, name
, now
, F_IPV4
| F_IPV6
)))
476 if (crecp
->flags
& F_DHCP
)
480 if ((crecp
->flags
& flag
) &&
481 (local_query
|| filter_zone(zone
, flag
, &(crecp
->addr
.addr
))))
483 *cut
= '.'; /* restore domain part */
484 log_query(crecp
->flags
, name
, &crecp
->addr
.addr
, record_source(crecp
->uid
));
485 *cut
= 0; /* remove domain part */
487 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
488 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
489 qtype
== T_A
? "4" : "6", &crecp
->addr
))
492 } while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
| F_IPV6
)));
495 *cut
= '.'; /* restore domain part */
498 if ((crecp
= cache_find_by_name(NULL
, name
, now
, F_IPV4
| F_IPV6
)))
500 if ((crecp
->flags
& F_HOSTS
) || (((crecp
->flags
& F_DHCP
) && option_bool(OPT_DHCP_FQDN
))))
504 if ((crecp
->flags
& flag
) && (local_query
|| filter_zone(zone
, flag
, &(crecp
->addr
.addr
))))
506 log_query(crecp
->flags
, name
, &crecp
->addr
.addr
, record_source(crecp
->uid
));
508 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
509 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
510 qtype
== T_A
? "4" : "6", &crecp
->addr
))
513 } while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
| F_IPV6
)));
517 log_query(flag
| F_NEG
| (nxdomain
? F_NXDOMAIN
: 0) | F_FORWARD
| F_AUTH
, name
, NULL
, NULL
);
521 /* Add auth section */
525 int newoffset
, offset
= 0;
528 authname
= zone
->domain
;
531 /* handle NS and SOA for PTR records */
535 if (!(subnet
->flags
& ADDRLIST_IPV6
))
537 in_addr_t a
= ntohl(subnet
->addr
.addr
.addr4
.s_addr
) >> 8;
540 if (subnet
->prefixlen
>= 24)
541 p
+= sprintf(p
, "%d.", a
& 0xff);
543 if (subnet
->prefixlen
>= 16 )
544 p
+= sprintf(p
, "%d.", a
& 0xff);
546 p
+= sprintf(p
, "%d.in-addr.arpa", a
& 0xff);
555 for (i
= subnet
->prefixlen
-1; i
>= 0; i
-= 4)
557 int dig
= ((unsigned char *)&subnet
->addr
.addr
.addr6
)[i
>>3];
558 p
+= sprintf(p
, "%.1x.", (i
>>2) & 1 ? dig
& 15 : dig
>> 4);
560 p
+= sprintf(p
, "ip6.arpa");
566 /* handle NS and SOA in auth section or for explicit queries */
567 newoffset
= ansp
- (unsigned char *)header
;
568 if (((anscount
== 0 && !ns
) || soa
) &&
569 add_resource_record(header
, limit
, &trunc
, 0, &ansp
,
570 daemon
->auth_ttl
, NULL
, T_SOA
, C_IN
, "ddlllll",
571 authname
, daemon
->authserver
, daemon
->hostmaster
,
572 daemon
->soa_sn
, daemon
->soa_refresh
,
573 daemon
->soa_retry
, daemon
->soa_expiry
,
583 if (anscount
!= 0 || ns
)
585 struct name_list
*secondary
;
587 newoffset
= ansp
- (unsigned char *)header
;
588 if (add_resource_record(header
, limit
, &trunc
, -offset
, &ansp
,
589 daemon
->auth_ttl
, NULL
, T_NS
, C_IN
, "d", offset
== 0 ? authname
: NULL
, daemon
->authserver
))
600 for (secondary
= daemon
->secondary_forward_server
; secondary
; secondary
= secondary
->next
)
601 if (add_resource_record(header
, limit
, &trunc
, offset
, &ansp
,
602 daemon
->auth_ttl
, NULL
, T_NS
, C_IN
, "d", secondary
->name
))
613 for (rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
614 if (in_zone(zone
, rec
->name
, &cut
))
621 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
622 NULL
, T_SRV
, C_IN
, "sssd", cut
? rec
->name
: NULL
,
623 rec
->priority
, rec
->weight
, rec
->srvport
, rec
->target
))
629 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
630 NULL
, T_MX
, C_IN
, "sd", cut
? rec
->name
: NULL
, rec
->weight
, rec
->target
))
634 /* restore config data */
639 for (txt
= daemon
->rr
; txt
; txt
= txt
->next
)
640 if (in_zone(zone
, txt
->name
, &cut
))
645 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
646 NULL
, txt
->class, C_IN
, "t", cut
? txt
->name
: NULL
, txt
->len
, txt
->txt
))
649 /* restore config data */
654 for (txt
= daemon
->txt
; txt
; txt
= txt
->next
)
655 if (txt
->class == C_IN
&& in_zone(zone
, txt
->name
, &cut
))
660 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
661 NULL
, T_TXT
, C_IN
, "t", cut
? txt
->name
: NULL
, txt
->len
, txt
->txt
))
664 /* restore config data */
669 for (na
= daemon
->naptr
; na
; na
= na
->next
)
670 if (in_zone(zone
, na
->name
, &cut
))
675 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
676 NULL
, T_NAPTR
, C_IN
, "sszzzd", cut
? na
->name
: NULL
,
677 na
->order
, na
->pref
, na
->flags
, na
->services
, na
->regexp
, na
->replace
))
680 /* restore config data */
685 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
686 if (in_zone(zone
, intr
->name
, &cut
))
688 struct addrlist
*addrlist
;
693 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
694 if (!(addrlist
->flags
& ADDRLIST_IPV6
) &&
695 (local_query
|| filter_zone(zone
, F_IPV4
, &addrlist
->addr
)) &&
696 add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
697 daemon
->auth_ttl
, NULL
, T_A
, C_IN
, "4", cut
? intr
->name
: NULL
, &addrlist
->addr
))
701 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
702 if ((addrlist
->flags
& ADDRLIST_IPV6
) &&
703 (local_query
|| filter_zone(zone
, F_IPV6
, &addrlist
->addr
)) &&
704 add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
705 daemon
->auth_ttl
, NULL
, T_AAAA
, C_IN
, "6", cut
? intr
->name
: NULL
, &addrlist
->addr
))
709 /* restore config data */
714 for (a
= daemon
->cnames
; a
; a
= a
->next
)
715 if (in_zone(zone
, a
->alias
, &cut
))
717 strcpy(name
, a
->target
);
718 if (!strchr(name
, '.'))
721 strcat(name
, zone
->domain
);
727 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
728 daemon
->auth_ttl
, NULL
,
729 T_CNAME
, C_IN
, "d", cut
? a
->alias
: NULL
, name
))
734 while ((crecp
= cache_enumerate(0)))
736 if ((crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
737 !(crecp
->flags
& (F_NEG
| F_NXDOMAIN
)) &&
738 (crecp
->flags
& F_FORWARD
))
740 if ((crecp
->flags
& F_DHCP
) && !option_bool(OPT_DHCP_FQDN
))
742 char *cache_name
= cache_get_name(crecp
);
743 if (!strchr(cache_name
, '.') &&
744 (local_query
|| filter_zone(zone
, (crecp
->flags
& (F_IPV6
| F_IPV4
)), &(crecp
->addr
.addr
))))
748 if (crecp
->flags
& F_IPV6
)
751 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
752 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
753 (crecp
->flags
& F_IPV4
) ? "4" : "6", cache_name
, &crecp
->addr
))
758 if ((crecp
->flags
& F_HOSTS
) || (((crecp
->flags
& F_DHCP
) && option_bool(OPT_DHCP_FQDN
))))
760 strcpy(name
, cache_get_name(crecp
));
761 if (in_zone(zone
, name
, &cut
) &&
762 (local_query
|| filter_zone(zone
, (crecp
->flags
& (F_IPV6
| F_IPV4
)), &(crecp
->addr
.addr
))))
766 if (crecp
->flags
& F_IPV6
)
772 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
773 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
774 (crecp
->flags
& F_IPV4
) ? "4" : "6", cut
? name
: NULL
, &crecp
->addr
))
781 /* repeat SOA as last record */
782 if (add_resource_record(header
, limit
, &trunc
, axfroffset
, &ansp
,
783 daemon
->auth_ttl
, NULL
, T_SOA
, C_IN
, "ddlllll",
784 daemon
->authserver
, daemon
->hostmaster
,
785 daemon
->soa_sn
, daemon
->soa_refresh
,
786 daemon
->soa_retry
, daemon
->soa_expiry
,
794 /* done all questions, set up header and return length of result */
795 /* clear authoritative and truncated flags, set QR flag */
796 header
->hb3
= (header
->hb3
& ~(HB3_AA
| HB3_TC
)) | HB3_QR
;
801 header
->hb4
|= HB4_RA
;
806 header
->hb4
&= ~HB4_RA
;
811 header
->hb3
|= HB3_AA
;
815 header
->hb3
|= HB3_TC
;
817 if ((auth
|| local_query
) && nxdomain
)
818 SET_RCODE(header
, NXDOMAIN
);
820 SET_RCODE(header
, NOERROR
); /* no error */
821 header
->ancount
= htons(anscount
);
822 header
->nscount
= htons(authcount
);
823 header
->arcount
= htons(0);
825 /* Advertise our packet size limit in our reply */
826 if (have_pseudoheader
)
827 return add_pseudoheader(header
, ansp
- (unsigned char *)header
, (unsigned char *)limit
, daemon
->edns_pktsz
, 0, NULL
, 0, do_bit
, 0);
829 return ansp
- (unsigned char *)header
;