1 /* dnsmasq is Copyright (c) 2000-2015 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
, int local_query
)
86 char *name
= daemon
->namebuff
;
87 unsigned char *p
, *ansp
;
89 int nameoffset
, axfroffset
= 0;
90 int q
, anscount
= 0, authcount
= 0;
92 int auth
= !local_query
, trunc
= 0, nxdomain
= 1, soa
= 0, ns
= 0, axfr
= 0;
93 struct auth_zone
*zone
= NULL
;
94 struct addrlist
*subnet
= NULL
;
96 struct mx_srv_record
*rec
, *move
, **up
;
97 struct txt_record
*txt
;
98 struct interface_name
*intr
;
100 struct all_addr addr
;
103 if (ntohs(header
->qdcount
) == 0 || OPCODE(header
) != QUERY
)
106 /* determine end of question section (we put answers there) */
107 if (!(ansp
= skip_questions(header
, qlen
)))
108 return 0; /* bad packet */
110 /* now process each question, answers go in RRs after the question */
111 p
= (unsigned char *)(header
+1);
113 for (q
= ntohs(header
->qdcount
); q
!= 0; q
--)
115 unsigned short flag
= 0;
118 /* save pointer to name for copying into answers */
119 nameoffset
= p
- (unsigned char *)header
;
121 /* now extract name as .-concatenated string into name */
122 if (!extract_name(header
, qlen
, &p
, name
, 1, 4))
123 return 0; /* bad packet */
134 if ((qtype
== T_PTR
|| qtype
== T_SOA
|| qtype
== T_NS
) &&
135 (flag
= in_arpa_name_2_addr(name
, &addr
)) &&
138 for (zone
= daemon
->auth_zones
; zone
; zone
= zone
->next
)
139 if ((subnet
= find_subnet(zone
, flag
, &addr
)))
147 else if (qtype
== T_SOA
)
149 else if (qtype
== T_NS
)
153 if (qtype
== T_PTR
&& flag
)
158 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
160 struct addrlist
*addrlist
;
162 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
163 if (!(addrlist
->flags
& ADDRLIST_IPV6
) && addr
.addr
.addr4
.s_addr
== addrlist
->addr
.addr
.addr4
.s_addr
)
169 while (intr
->next
&& strcmp(intr
->intr
, intr
->next
->intr
) == 0)
173 else if (flag
== F_IPV6
)
174 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
176 struct addrlist
*addrlist
;
178 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
179 if ((addrlist
->flags
& ADDRLIST_IPV6
) && IN6_ARE_ADDR_EQUAL(&addr
.addr
.addr6
, &addrlist
->addr
.addr
.addr6
))
185 while (intr
->next
&& strcmp(intr
->intr
, intr
->next
->intr
) == 0)
192 if (local_query
|| in_zone(zone
, intr
->name
, NULL
))
195 log_query(flag
| F_REVERSE
| F_CONFIG
, intr
->name
, &addr
, NULL
);
196 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
197 daemon
->auth_ttl
, NULL
,
198 T_PTR
, C_IN
, "d", intr
->name
))
203 if ((crecp
= cache_find_by_addr(NULL
, &addr
, now
, flag
)))
205 strcpy(name
, cache_get_name(crecp
));
207 if (crecp
->flags
& F_DHCP
&& !option_bool(OPT_DHCP_FQDN
))
209 char *p
= strchr(name
, '.');
211 *p
= 0; /* must be bare name */
213 /* add external domain */
217 strcat(name
, zone
->domain
);
219 log_query(flag
| F_DHCP
| F_REVERSE
, name
, &addr
, record_source(crecp
->uid
));
221 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
222 daemon
->auth_ttl
, NULL
,
223 T_PTR
, C_IN
, "d", name
))
226 else if (crecp
->flags
& (F_DHCP
| F_HOSTS
) && (local_query
|| in_zone(zone
, name
, NULL
)))
228 log_query(crecp
->flags
& ~F_FORWARD
, name
, &addr
, record_source(crecp
->uid
));
230 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
231 daemon
->auth_ttl
, NULL
,
232 T_PTR
, C_IN
, "d", name
))
238 } while ((crecp
= cache_find_by_addr(crecp
, &addr
, now
, flag
)));
243 log_query(flag
| F_NEG
| F_NXDOMAIN
| F_REVERSE
| (auth
? F_AUTH
: 0), NULL
, &addr
, NULL
);
250 /* NS and SOA .arpa requests have set found above. */
254 for (zone
= daemon
->auth_zones
; zone
; zone
= zone
->next
)
255 if (in_zone(zone
, name
, &cut
))
265 for (rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
266 if (!rec
->issrv
&& hostname_isequal(name
, rec
->name
))
273 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<MX>");
274 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
275 NULL
, T_MX
, C_IN
, "sd", rec
->weight
, rec
->target
))
280 for (move
= NULL
, up
= &daemon
->mxnames
, rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
281 if (rec
->issrv
&& hostname_isequal(name
, rec
->name
))
288 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<SRV>");
289 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
290 NULL
, T_SRV
, C_IN
, "sssd",
291 rec
->priority
, rec
->weight
, rec
->srvport
, rec
->target
))
296 /* unlink first SRV record found */
308 /* put first SRV record back at the end. */
315 for (txt
= daemon
->rr
; txt
; txt
= txt
->next
)
316 if (hostname_isequal(name
, txt
->name
))
319 if (txt
->class == qtype
)
322 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<RR>");
323 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
324 NULL
, txt
->class, C_IN
, "t", txt
->len
, txt
->txt
))
329 for (txt
= daemon
->txt
; txt
; txt
= txt
->next
)
330 if (txt
->class == C_IN
&& hostname_isequal(name
, txt
->name
))
336 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<TXT>");
337 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
338 NULL
, T_TXT
, C_IN
, "t", txt
->len
, txt
->txt
))
343 for (na
= daemon
->naptr
; na
; na
= na
->next
)
344 if (hostname_isequal(name
, na
->name
))
347 if (qtype
== T_NAPTR
)
350 log_query(F_CONFIG
| F_RRNAME
, name
, NULL
, "<NAPTR>");
351 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
, daemon
->auth_ttl
,
352 NULL
, T_NAPTR
, C_IN
, "sszzzd",
353 na
->order
, na
->pref
, na
->flags
, na
->services
, na
->regexp
, na
->replace
))
366 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
367 if (hostname_isequal(name
, intr
->name
))
369 struct addrlist
*addrlist
;
374 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
375 if (((addrlist
->flags
& ADDRLIST_IPV6
) ? T_AAAA
: T_A
) == qtype
&&
376 (local_query
|| filter_zone(zone
, flag
, &addrlist
->addr
)))
379 if (addrlist
->flags
& ADDRLIST_REVONLY
)
383 log_query(F_FORWARD
| F_CONFIG
| flag
, name
, &addrlist
->addr
, NULL
);
384 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
385 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
386 qtype
== T_A
? "4" : "6", &addrlist
->addr
))
391 for (a
= daemon
->cnames
; a
; a
= a
->next
)
392 if (hostname_isequal(name
, a
->alias
) )
394 log_query(F_CONFIG
| F_CNAME
, name
, NULL
, NULL
);
395 strcpy(name
, a
->target
);
396 if (!strchr(name
, '.'))
399 strcat(name
, zone
->domain
);
402 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
403 daemon
->auth_ttl
, &nameoffset
,
404 T_CNAME
, C_IN
, "d", name
))
416 auth
= soa
= 1; /* inhibits auth section */
418 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<SOA>");
420 else if (qtype
== T_AXFR
)
424 if (peer_addr
->sa
.sa_family
== AF_INET
)
425 peer_addr
->in
.sin_port
= 0;
429 peer_addr
->in6
.sin6_port
= 0;
430 peer_addr
->in6
.sin6_scope_id
= 0;
434 for (peers
= daemon
->auth_peers
; peers
; peers
= peers
->next
)
435 if (sockaddr_isequal(peer_addr
, &peers
->addr
))
438 /* Refuse all AXFR unless --auth-sec-servers is set */
439 if ((!peers
&& daemon
->auth_peers
) || !daemon
->secondary_forward_server
)
441 if (peer_addr
->sa
.sa_family
== AF_INET
)
442 inet_ntop(AF_INET
, &peer_addr
->in
.sin_addr
, daemon
->addrbuff
, ADDRSTRLEN
);
445 inet_ntop(AF_INET6
, &peer_addr
->in6
.sin6_addr
, daemon
->addrbuff
, ADDRSTRLEN
);
448 my_syslog(LOG_WARNING
, _("ignoring zone transfer request from %s"), daemon
->addrbuff
);
453 soa
= 1; /* inhibits auth section */
454 ns
= 1; /* ensure we include NS records! */
457 axfroffset
= nameoffset
;
458 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<AXFR>");
460 else if (qtype
== T_NS
)
463 ns
= 1; /* inhibits auth section */
465 log_query(F_RRNAME
| F_AUTH
, zone
->domain
, NULL
, "<NS>");
469 if (!option_bool(OPT_DHCP_FQDN
) && cut
)
471 *cut
= 0; /* remove domain part */
473 if (!strchr(name
, '.') && (crecp
= cache_find_by_name(NULL
, name
, now
, F_IPV4
| F_IPV6
)))
475 if (crecp
->flags
& F_DHCP
)
479 if ((crecp
->flags
& flag
) &&
480 (local_query
|| filter_zone(zone
, flag
, &(crecp
->addr
.addr
))))
482 *cut
= '.'; /* restore domain part */
483 log_query(crecp
->flags
, name
, &crecp
->addr
.addr
, record_source(crecp
->uid
));
484 *cut
= 0; /* remove domain part */
486 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
487 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
488 qtype
== T_A
? "4" : "6", &crecp
->addr
))
491 } while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
| F_IPV6
)));
494 *cut
= '.'; /* restore domain part */
497 if ((crecp
= cache_find_by_name(NULL
, name
, now
, F_IPV4
| F_IPV6
)))
499 if ((crecp
->flags
& F_HOSTS
) || (((crecp
->flags
& F_DHCP
) && option_bool(OPT_DHCP_FQDN
))))
503 if ((crecp
->flags
& flag
) && (local_query
|| filter_zone(zone
, flag
, &(crecp
->addr
.addr
))))
505 log_query(crecp
->flags
, name
, &crecp
->addr
.addr
, record_source(crecp
->uid
));
507 if (add_resource_record(header
, limit
, &trunc
, nameoffset
, &ansp
,
508 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
509 qtype
== T_A
? "4" : "6", &crecp
->addr
))
512 } while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
| F_IPV6
)));
516 log_query(flag
| F_NEG
| (nxdomain
? F_NXDOMAIN
: 0) | F_FORWARD
| F_AUTH
, name
, NULL
, NULL
);
520 /* Add auth section */
524 int newoffset
, offset
= 0;
527 authname
= zone
->domain
;
530 /* handle NS and SOA for PTR records */
534 if (!(subnet
->flags
& ADDRLIST_IPV6
))
536 in_addr_t a
= ntohl(subnet
->addr
.addr
.addr4
.s_addr
) >> 8;
539 if (subnet
->prefixlen
>= 24)
540 p
+= sprintf(p
, "%d.", a
& 0xff);
542 if (subnet
->prefixlen
>= 16 )
543 p
+= sprintf(p
, "%d.", a
& 0xff);
545 p
+= sprintf(p
, "%d.in-addr.arpa", a
& 0xff);
554 for (i
= subnet
->prefixlen
-1; i
>= 0; i
-= 4)
556 int dig
= ((unsigned char *)&subnet
->addr
.addr
.addr6
)[i
>>3];
557 p
+= sprintf(p
, "%.1x.", (i
>>2) & 1 ? dig
& 15 : dig
>> 4);
559 p
+= sprintf(p
, "ip6.arpa");
565 /* handle NS and SOA in auth section or for explicit queries */
566 newoffset
= ansp
- (unsigned char *)header
;
567 if (((anscount
== 0 && !ns
) || soa
) &&
568 add_resource_record(header
, limit
, &trunc
, 0, &ansp
,
569 daemon
->auth_ttl
, NULL
, T_SOA
, C_IN
, "ddlllll",
570 authname
, daemon
->authserver
, daemon
->hostmaster
,
571 daemon
->soa_sn
, daemon
->soa_refresh
,
572 daemon
->soa_retry
, daemon
->soa_expiry
,
582 if (anscount
!= 0 || ns
)
584 struct name_list
*secondary
;
586 newoffset
= ansp
- (unsigned char *)header
;
587 if (add_resource_record(header
, limit
, &trunc
, -offset
, &ansp
,
588 daemon
->auth_ttl
, NULL
, T_NS
, C_IN
, "d", offset
== 0 ? authname
: NULL
, daemon
->authserver
))
599 for (secondary
= daemon
->secondary_forward_server
; secondary
; secondary
= secondary
->next
)
600 if (add_resource_record(header
, limit
, &trunc
, offset
, &ansp
,
601 daemon
->auth_ttl
, NULL
, T_NS
, C_IN
, "d", secondary
->name
))
612 for (rec
= daemon
->mxnames
; rec
; rec
= rec
->next
)
613 if (in_zone(zone
, rec
->name
, &cut
))
620 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
621 NULL
, T_SRV
, C_IN
, "sssd", cut
? rec
->name
: NULL
,
622 rec
->priority
, rec
->weight
, rec
->srvport
, rec
->target
))
628 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
629 NULL
, T_MX
, C_IN
, "sd", cut
? rec
->name
: NULL
, rec
->weight
, rec
->target
))
633 /* restore config data */
638 for (txt
= daemon
->rr
; txt
; txt
= txt
->next
)
639 if (in_zone(zone
, txt
->name
, &cut
))
644 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
645 NULL
, txt
->class, C_IN
, "t", cut
? txt
->name
: NULL
, txt
->len
, txt
->txt
))
648 /* restore config data */
653 for (txt
= daemon
->txt
; txt
; txt
= txt
->next
)
654 if (txt
->class == C_IN
&& in_zone(zone
, txt
->name
, &cut
))
659 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
660 NULL
, T_TXT
, C_IN
, "t", cut
? txt
->name
: NULL
, txt
->len
, txt
->txt
))
663 /* restore config data */
668 for (na
= daemon
->naptr
; na
; na
= na
->next
)
669 if (in_zone(zone
, na
->name
, &cut
))
674 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
, daemon
->auth_ttl
,
675 NULL
, T_NAPTR
, C_IN
, "sszzzd", cut
? na
->name
: NULL
,
676 na
->order
, na
->pref
, na
->flags
, na
->services
, na
->regexp
, na
->replace
))
679 /* restore config data */
684 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
685 if (in_zone(zone
, intr
->name
, &cut
))
687 struct addrlist
*addrlist
;
692 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
693 if (!(addrlist
->flags
& ADDRLIST_IPV6
) &&
694 (local_query
|| filter_zone(zone
, F_IPV4
, &addrlist
->addr
)) &&
695 add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
696 daemon
->auth_ttl
, NULL
, T_A
, C_IN
, "4", cut
? intr
->name
: NULL
, &addrlist
->addr
))
700 for (addrlist
= intr
->addr
; addrlist
; addrlist
= addrlist
->next
)
701 if ((addrlist
->flags
& ADDRLIST_IPV6
) &&
702 (local_query
|| filter_zone(zone
, F_IPV6
, &addrlist
->addr
)) &&
703 add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
704 daemon
->auth_ttl
, NULL
, T_AAAA
, C_IN
, "6", cut
? intr
->name
: NULL
, &addrlist
->addr
))
708 /* restore config data */
713 for (a
= daemon
->cnames
; a
; a
= a
->next
)
714 if (in_zone(zone
, a
->alias
, &cut
))
716 strcpy(name
, a
->target
);
717 if (!strchr(name
, '.'))
720 strcat(name
, zone
->domain
);
726 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
727 daemon
->auth_ttl
, NULL
,
728 T_CNAME
, C_IN
, "d", cut
? a
->alias
: NULL
, name
))
733 while ((crecp
= cache_enumerate(0)))
735 if ((crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
736 !(crecp
->flags
& (F_NEG
| F_NXDOMAIN
)) &&
737 (crecp
->flags
& F_FORWARD
))
739 if ((crecp
->flags
& F_DHCP
) && !option_bool(OPT_DHCP_FQDN
))
741 char *cache_name
= cache_get_name(crecp
);
742 if (!strchr(cache_name
, '.') &&
743 (local_query
|| filter_zone(zone
, (crecp
->flags
& (F_IPV6
| F_IPV4
)), &(crecp
->addr
.addr
))))
747 if (crecp
->flags
& F_IPV6
)
750 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
751 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
752 (crecp
->flags
& F_IPV4
) ? "4" : "6", cache_name
, &crecp
->addr
))
757 if ((crecp
->flags
& F_HOSTS
) || (((crecp
->flags
& F_DHCP
) && option_bool(OPT_DHCP_FQDN
))))
759 strcpy(name
, cache_get_name(crecp
));
760 if (in_zone(zone
, name
, &cut
) &&
761 (local_query
|| filter_zone(zone
, (crecp
->flags
& (F_IPV6
| F_IPV4
)), &(crecp
->addr
.addr
))))
765 if (crecp
->flags
& F_IPV6
)
771 if (add_resource_record(header
, limit
, &trunc
, -axfroffset
, &ansp
,
772 daemon
->auth_ttl
, NULL
, qtype
, C_IN
,
773 (crecp
->flags
& F_IPV4
) ? "4" : "6", cut
? name
: NULL
, &crecp
->addr
))
780 /* repeat SOA as last record */
781 if (add_resource_record(header
, limit
, &trunc
, axfroffset
, &ansp
,
782 daemon
->auth_ttl
, NULL
, T_SOA
, C_IN
, "ddlllll",
783 daemon
->authserver
, daemon
->hostmaster
,
784 daemon
->soa_sn
, daemon
->soa_refresh
,
785 daemon
->soa_retry
, daemon
->soa_expiry
,
793 /* done all questions, set up header and return length of result */
794 /* clear authoritative and truncated flags, set QR flag */
795 header
->hb3
= (header
->hb3
& ~(HB3_AA
| HB3_TC
)) | HB3_QR
;
800 header
->hb4
|= HB4_RA
;
805 header
->hb4
&= ~HB4_RA
;
810 header
->hb3
|= HB3_AA
;
814 header
->hb3
|= HB3_TC
;
816 if ((auth
|| local_query
) && nxdomain
)
817 SET_RCODE(header
, NXDOMAIN
);
819 SET_RCODE(header
, NOERROR
); /* no error */
820 header
->ancount
= htons(anscount
);
821 header
->nscount
= htons(authcount
);
822 header
->arcount
= htons(0);
823 return ansp
- (unsigned char *)header
;