version 1.1.1.2, 2014/06/15 16:31:38
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 18
|
Line 18
|
|
|
#ifdef HAVE_AUTH |
#ifdef HAVE_AUTH |
|
|
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u) | static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u) |
{ |
{ |
struct addrlist *subnet; | do { |
| if (!(list->flags & ADDRLIST_IPV6)) |
| { |
| struct in_addr netmask, addr = addr_u->addr4; |
| |
| if (!(flag & F_IPV4)) |
| continue; |
| |
| netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen)); |
| |
| if (is_same_net(addr, list->addr.addr4, netmask)) |
| return list; |
| } |
| else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen)) |
| return list; |
| |
| } while ((list = list->next)); |
| |
| return NULL; |
| } |
|
|
for (subnet = zone->subnet; subnet; subnet = subnet->next) | static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u) |
{ | { |
if (!(subnet->flags & ADDRLIST_IPV6)) | if (!zone->subnet) |
{ | return NULL; |
struct in_addr netmask, addr = addr_u->addr.addr4; | |
| return find_addrlist(zone->subnet, flag, addr_u); |
| } |
|
|
if (!(flag & F_IPV4)) | static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u) |
continue; | { |
| if (!zone->exclude) |
netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1)); | return NULL; |
| |
if (is_same_net(addr, subnet->addr.addr.addr4, netmask)) | return find_addrlist(zone->exclude, flag, addr_u); |
return subnet; | |
} | |
#ifdef HAVE_IPV6 | |
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen)) | |
return subnet; | |
#endif | |
| |
} | |
return NULL; | |
} |
} |
|
|
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) | static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u) |
{ |
{ |
/* No zones specified, no filter */ | if (find_exclude(zone, flag, addr_u)) |
| return 0; |
| |
| /* No subnets specified, no filter */ |
if (!zone->subnet) |
if (!zone->subnet) |
return 1; |
return 1; |
|
|
Line 81 int in_zone(struct auth_zone *zone, char *name, char *
|
Line 96 int in_zone(struct auth_zone *zone, char *name, char *
|
} |
} |
|
|
|
|
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) | size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, |
| int local_query, int do_bit, int have_pseudoheader) |
{ |
{ |
char *name = daemon->namebuff; |
char *name = daemon->namebuff; |
unsigned char *p, *ansp; |
unsigned char *p, *ansp; |
int qtype, qclass; | int qtype, qclass, rc; |
int nameoffset, axfroffset = 0; |
int nameoffset, axfroffset = 0; |
int q, anscount = 0, authcount = 0; |
int q, anscount = 0, authcount = 0; |
struct crec *crecp; |
struct crec *crecp; |
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; | int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0; |
struct auth_zone *zone = NULL; |
struct auth_zone *zone = NULL; |
struct addrlist *subnet = NULL; |
struct addrlist *subnet = NULL; |
char *cut; |
char *cut; |
Line 97 size_t answer_auth(struct dns_header *header, char *li
|
Line 113 size_t answer_auth(struct dns_header *header, char *li
|
struct txt_record *txt; |
struct txt_record *txt; |
struct interface_name *intr; |
struct interface_name *intr; |
struct naptr *na; |
struct naptr *na; |
struct all_addr addr; | union all_addr addr; |
struct cname *a; | struct cname *a, *candidate; |
| unsigned int wclen; |
|
|
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) |
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) |
return 0; |
return 0; |
Line 112 size_t answer_auth(struct dns_header *header, char *li
|
Line 129 size_t answer_auth(struct dns_header *header, char *li
|
|
|
for (q = ntohs(header->qdcount); q != 0; q--) |
for (q = ntohs(header->qdcount); q != 0; q--) |
{ |
{ |
unsigned short flag = 0; | unsigned int flag = 0; |
int found = 0; |
int found = 0; |
|
int cname_wildcard = 0; |
|
|
/* save pointer to name for copying into answers */ |
/* save pointer to name for copying into answers */ |
nameoffset = p - (unsigned char *)header; |
nameoffset = p - (unsigned char *)header; |
Line 128 size_t answer_auth(struct dns_header *header, char *li
|
Line 146 size_t answer_auth(struct dns_header *header, char *li
|
if (qclass != C_IN) |
if (qclass != C_IN) |
{ |
{ |
auth = 0; |
auth = 0; |
|
out_of_zone = 1; |
continue; |
continue; |
} |
} |
|
|
if (qtype == T_PTR) | if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) && |
| (flag = in_arpa_name_2_addr(name, &addr)) && |
| !local_query) |
{ |
{ |
if (!(flag = in_arpa_name_2_addr(name, &addr))) | for (zone = daemon->auth_zones; zone; zone = zone->next) |
continue; | if ((subnet = find_subnet(zone, flag, &addr))) |
| break; |
if (!local_query) | |
| if (!zone) |
{ |
{ |
for (zone = daemon->auth_zones; zone; zone = zone->next) | out_of_zone = 1; |
if ((subnet = find_subnet(zone, flag, &addr))) | auth = 0; |
break; | continue; |
| |
if (!zone) | |
{ | |
auth = 0; | |
continue; | |
} | |
} |
} |
|
else if (qtype == T_SOA) |
|
soa = 1, found = 1; |
|
else if (qtype == T_NS) |
|
ns = 1, found = 1; |
|
} |
|
|
|
if (qtype == T_PTR && flag) |
|
{ |
intr = NULL; |
intr = NULL; |
|
|
if (flag == F_IPV4) |
if (flag == F_IPV4) |
Line 157 size_t answer_auth(struct dns_header *header, char *li
|
Line 180 size_t answer_auth(struct dns_header *header, char *li
|
struct addrlist *addrlist; |
struct addrlist *addrlist; |
|
|
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr) | if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr) |
break; |
break; |
|
|
if (addrlist) |
if (addrlist) |
Line 166 size_t answer_auth(struct dns_header *header, char *li
|
Line 189 size_t answer_auth(struct dns_header *header, char *li
|
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
intr = intr->next; |
intr = intr->next; |
} |
} |
#ifdef HAVE_IPV6 |
|
else if (flag == F_IPV6) |
else if (flag == F_IPV6) |
for (intr = daemon->int_names; intr; intr = intr->next) |
for (intr = daemon->int_names; intr; intr = intr->next) |
{ |
{ |
struct addrlist *addrlist; |
struct addrlist *addrlist; |
|
|
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6)) | if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6)) |
break; |
break; |
|
|
if (addrlist) |
if (addrlist) |
Line 182 size_t answer_auth(struct dns_header *header, char *li
|
Line 204 size_t answer_auth(struct dns_header *header, char *li
|
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
intr = intr->next; |
intr = intr->next; |
} |
} |
#endif |
|
|
|
if (intr) |
if (intr) |
{ |
{ |
if (in_zone(zone, intr->name, NULL)) | if (local_query || in_zone(zone, intr->name, NULL)) |
{ |
{ |
found = 1; |
found = 1; |
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); | log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, |
daemon->auth_ttl, NULL, |
T_PTR, C_IN, "d", intr->name)) |
T_PTR, C_IN, "d", intr->name)) |
Line 208 size_t answer_auth(struct dns_header *header, char *li
|
Line 229 size_t answer_auth(struct dns_header *header, char *li
|
*p = 0; /* must be bare name */ |
*p = 0; /* must be bare name */ |
|
|
/* add external domain */ |
/* add external domain */ |
strcat(name, "."); | if (zone) |
strcat(name, zone->domain); | { |
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid)); | strcat(name, "."); |
| strcat(name, zone->domain); |
| } |
| log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0); |
found = 1; |
found = 1; |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, |
daemon->auth_ttl, NULL, |
T_PTR, C_IN, "d", name)) |
T_PTR, C_IN, "d", name)) |
anscount++; |
anscount++; |
} |
} |
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL)) | else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL))) |
{ |
{ |
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid)); | log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0); |
found = 1; |
found = 1; |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, |
daemon->auth_ttl, NULL, |
Line 231 size_t answer_auth(struct dns_header *header, char *li
|
Line 255 size_t answer_auth(struct dns_header *header, char *li
|
|
|
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag))); |
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag))); |
|
|
|
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL))) |
|
{ |
|
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0); |
|
found = 1; |
|
|
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
|
daemon->auth_ttl, NULL, |
|
T_PTR, C_IN, "d", name)) |
|
anscount++; |
|
} |
|
|
if (found) |
if (found) |
nxdomain = 0; |
nxdomain = 0; |
else |
else |
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL); | log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0); |
|
|
continue; |
continue; |
} |
} |
|
|
cname_restart: |
cname_restart: |
for (zone = daemon->auth_zones; zone; zone = zone->next) | if (found) |
if (in_zone(zone, name, &cut)) | /* NS and SOA .arpa requests have set found above. */ |
break; | cut = NULL; |
| else |
if (!zone) | |
{ |
{ |
auth = 0; | for (zone = daemon->auth_zones; zone; zone = zone->next) |
continue; | if (in_zone(zone, name, &cut)) |
| break; |
| |
| if (!zone) |
| { |
| out_of_zone = 1; |
| auth = 0; |
| continue; |
| } |
} |
} |
|
|
for (rec = daemon->mxnames; rec; rec = rec->next) |
for (rec = daemon->mxnames; rec; rec = rec->next) |
if (!rec->issrv && hostname_isequal(name, rec->name)) | if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name))) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
|
|
if (qtype == T_MX) | if (rc == 2 && qtype == T_MX) |
{ |
{ |
found = 1; |
found = 1; |
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); | log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) |
NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) |
anscount++; |
anscount++; |
Line 266 size_t answer_auth(struct dns_header *header, char *li
|
Line 308 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
|
|
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) |
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) |
if (rec->issrv && hostname_isequal(name, rec->name)) | if (rec->issrv && (rc = hostname_issubdomain(name, rec->name))) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
|
|
if (qtype == T_SRV) | if (rc == 2 && qtype == T_SRV) |
{ |
{ |
found = 1; |
found = 1; |
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); | log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
NULL, T_SRV, C_IN, "sssd", |
NULL, T_SRV, C_IN, "sssd", |
rec->priority, rec->weight, rec->srvport, rec->target)) |
rec->priority, rec->weight, rec->srvport, rec->target)) |
Line 301 size_t answer_auth(struct dns_header *header, char *li
|
Line 343 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
|
|
for (txt = daemon->rr; txt; txt = txt->next) |
for (txt = daemon->rr; txt; txt = txt->next) |
if (hostname_isequal(name, txt->name)) | if ((rc = hostname_issubdomain(name, txt->name))) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if (txt->class == qtype) | if (rc == 2 && txt->class == qtype) |
{ |
{ |
found = 1; |
found = 1; |
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); | log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
NULL, txt->class, C_IN, "t", txt->len, txt->txt)) |
NULL, txt->class, C_IN, "t", txt->len, txt->txt)) |
anscount++; |
anscount++; |
Line 315 size_t answer_auth(struct dns_header *header, char *li
|
Line 357 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
|
|
for (txt = daemon->txt; txt; txt = txt->next) |
for (txt = daemon->txt; txt; txt = txt->next) |
if (txt->class == C_IN && hostname_isequal(name, txt->name)) | if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name))) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if (qtype == T_TXT) | if (rc == 2 && qtype == T_TXT) |
{ |
{ |
found = 1; |
found = 1; |
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); | log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) |
NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) |
anscount++; |
anscount++; |
Line 329 size_t answer_auth(struct dns_header *header, char *li
|
Line 371 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
|
|
for (na = daemon->naptr; na; na = na->next) |
for (na = daemon->naptr; na; na = na->next) |
if (hostname_isequal(name, na->name)) | if ((rc = hostname_issubdomain(name, na->name))) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if (qtype == T_NAPTR) | if (rc == 2 && qtype == T_NAPTR) |
{ |
{ |
found = 1; |
found = 1; |
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>"); | log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, |
NULL, T_NAPTR, C_IN, "sszzzd", |
NULL, T_NAPTR, C_IN, "sszzzd", |
na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) |
na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) |
Line 346 size_t answer_auth(struct dns_header *header, char *li
|
Line 388 size_t answer_auth(struct dns_header *header, char *li
|
if (qtype == T_A) |
if (qtype == T_A) |
flag = F_IPV4; |
flag = F_IPV4; |
|
|
#ifdef HAVE_IPV6 |
|
if (qtype == T_AAAA) |
if (qtype == T_AAAA) |
flag = F_IPV6; |
flag = F_IPV6; |
#endif |
|
|
|
for (intr = daemon->int_names; intr; intr = intr->next) |
for (intr = daemon->int_names; intr; intr = intr->next) |
if (hostname_isequal(name, intr->name)) | if ((rc = hostname_issubdomain(name, intr->name))) |
{ |
{ |
struct addrlist *addrlist; |
struct addrlist *addrlist; |
|
|
nxdomain = 0; |
nxdomain = 0; |
|
|
if (flag) | if (rc == 2 && flag) |
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && |
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && |
(local_query || filter_zone(zone, flag, &addrlist->addr))) |
(local_query || filter_zone(zone, flag, &addrlist->addr))) |
{ |
{ |
|
if (addrlist->flags & ADDRLIST_REVONLY) |
|
continue; |
|
|
found = 1; |
found = 1; |
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL); | log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0); |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, qtype, C_IN, |
daemon->auth_ttl, NULL, qtype, C_IN, |
qtype == T_A ? "4" : "6", &addrlist->addr)) |
qtype == T_A ? "4" : "6", &addrlist->addr)) |
anscount++; |
anscount++; |
} |
} |
} |
} |
|
|
for (a = daemon->cnames; a; a = a->next) |
|
if (hostname_isequal(name, a->alias) ) |
|
{ |
|
log_query(F_CONFIG | F_CNAME, name, NULL, NULL); |
|
strcpy(name, a->target); |
|
if (!strchr(name, '.')) |
|
{ |
|
strcat(name, "."); |
|
strcat(name, zone->domain); |
|
} |
|
found = 1; |
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
|
daemon->auth_ttl, &nameoffset, |
|
T_CNAME, C_IN, "d", name)) |
|
anscount++; |
|
|
|
goto cname_restart; |
|
} |
|
|
|
|
if (!found && is_name_synthetic(flag, name, &addr) ) |
|
{ |
|
nxdomain = 0; |
|
|
|
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0); |
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
|
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr)) |
|
anscount++; |
|
} |
|
|
if (!cut) |
if (!cut) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
Line 398 size_t answer_auth(struct dns_header *header, char *li
|
Line 432 size_t answer_auth(struct dns_header *header, char *li
|
if (qtype == T_SOA) |
if (qtype == T_SOA) |
{ |
{ |
auth = soa = 1; /* inhibits auth section */ |
auth = soa = 1; /* inhibits auth section */ |
found = 1; | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0); |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); | |
} |
} |
else if (qtype == T_AXFR) |
else if (qtype == T_AXFR) |
{ |
{ |
Line 407 size_t answer_auth(struct dns_header *header, char *li
|
Line 440 size_t answer_auth(struct dns_header *header, char *li
|
|
|
if (peer_addr->sa.sa_family == AF_INET) |
if (peer_addr->sa.sa_family == AF_INET) |
peer_addr->in.sin_port = 0; |
peer_addr->in.sin_port = 0; |
#ifdef HAVE_IPV6 |
|
else |
else |
peer_addr->in6.sin6_port = 0; | { |
#endif | peer_addr->in6.sin6_port = 0; |
| peer_addr->in6.sin6_scope_id = 0; |
| } |
|
|
for (peers = daemon->auth_peers; peers; peers = peers->next) |
for (peers = daemon->auth_peers; peers; peers = peers->next) |
if (sockaddr_isequal(peer_addr, &peers->addr)) |
if (sockaddr_isequal(peer_addr, &peers->addr)) |
break; |
break; |
|
|
/* Refuse all AXFR unless --auth-sec-servers is set */ | /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */ |
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server) | if ((!daemon->secondary_forward_server && !daemon->auth_peers) || |
| (daemon->auth_peers && !peers)) |
{ |
{ |
if (peer_addr->sa.sa_family == AF_INET) |
if (peer_addr->sa.sa_family == AF_INET) |
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); |
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); |
#ifdef HAVE_IPV6 |
|
else |
else |
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); |
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); |
#endif |
|
|
|
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); |
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); |
return 0; |
return 0; |
Line 434 size_t answer_auth(struct dns_header *header, char *li
|
Line 467 size_t answer_auth(struct dns_header *header, char *li
|
soa = 1; /* inhibits auth section */ |
soa = 1; /* inhibits auth section */ |
ns = 1; /* ensure we include NS records! */ |
ns = 1; /* ensure we include NS records! */ |
axfr = 1; |
axfr = 1; |
found = 1; |
|
axfroffset = nameoffset; |
axfroffset = nameoffset; |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>"); | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0); |
} |
} |
else if (qtype == T_NS) |
else if (qtype == T_NS) |
{ |
{ |
auth = 1; |
auth = 1; |
ns = 1; /* inhibits auth section */ |
ns = 1; /* inhibits auth section */ |
found = 1; | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0); |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); | |
} |
} |
} |
} |
|
|
Line 458 size_t answer_auth(struct dns_header *header, char *li
|
Line 489 size_t answer_auth(struct dns_header *header, char *li
|
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if ((crecp->flags & flag) && |
if ((crecp->flags & flag) && |
(local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) | (local_query || filter_zone(zone, flag, &(crecp->addr)))) |
{ |
{ |
*cut = '.'; /* restore domain part */ |
*cut = '.'; /* restore domain part */ |
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); | log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0); |
*cut = 0; /* remove domain part */ |
*cut = 0; /* remove domain part */ |
found = 1; |
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, qtype, C_IN, |
daemon->auth_ttl, NULL, qtype, C_IN, |
qtype == T_A ? "4" : "6", &crecp->addr)) |
qtype == T_A ? "4" : "6", &crecp->addr)) |
Line 481 size_t answer_auth(struct dns_header *header, char *li
|
Line 511 size_t answer_auth(struct dns_header *header, char *li
|
do |
do |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) | if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr)))) |
{ |
{ |
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); | log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0); |
found = 1; | |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
daemon->auth_ttl, NULL, qtype, C_IN, |
daemon->auth_ttl, NULL, qtype, C_IN, |
qtype == T_A ? "4" : "6", &crecp->addr)) |
qtype == T_A ? "4" : "6", &crecp->addr)) |
Line 493 size_t answer_auth(struct dns_header *header, char *li
|
Line 522 size_t answer_auth(struct dns_header *header, char *li
|
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); |
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); |
} |
} |
|
|
if (!found) | /* Only supply CNAME if no record for any type is known. */ |
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); | if (nxdomain) |
| { |
| /* Check for possible wildcard match against *.domain |
| return length of match, to get longest. |
| Note that if return length of wildcard section, so |
| we match b.simon to _both_ *.simon and b.simon |
| but return a longer (better) match to b.simon. |
| */ |
| for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next) |
| if (a->alias[0] == '*') |
| { |
| char *test = name; |
| |
| while ((test = strchr(test+1, '.'))) |
| { |
| if (hostname_isequal(test, &(a->alias[1]))) |
| { |
| if (strlen(test) > wclen && !cname_wildcard) |
| { |
| wclen = strlen(test); |
| candidate = a; |
| cname_wildcard = 1; |
| } |
| break; |
| } |
| } |
| |
| } |
| else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen) |
| { |
| /* Simple case, no wildcard */ |
| wclen = strlen(a->alias); |
| candidate = a; |
| } |
| |
| if (candidate) |
| { |
| log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0); |
| strcpy(name, candidate->target); |
| if (!strchr(name, '.')) |
| { |
| strcat(name, "."); |
| strcat(name, zone->domain); |
| } |
| found = 1; |
| if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
| daemon->auth_ttl, &nameoffset, |
| T_CNAME, C_IN, "d", name)) |
| anscount++; |
| |
| goto cname_restart; |
| } |
| else if (cache_find_non_terminal(name, now)) |
| nxdomain = 0; |
| |
| log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0); |
| } |
|
|
} |
} |
|
|
Line 514 size_t answer_auth(struct dns_header *header, char *li
|
Line 599 size_t answer_auth(struct dns_header *header, char *li
|
|
|
if (!(subnet->flags & ADDRLIST_IPV6)) |
if (!(subnet->flags & ADDRLIST_IPV6)) |
{ |
{ |
in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8; | in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8; |
char *p = name; |
char *p = name; |
|
|
if (subnet->prefixlen >= 24) |
if (subnet->prefixlen >= 24) |
p += sprintf(p, "%d.", a & 0xff); | p += sprintf(p, "%u.", a & 0xff); |
a = a >> 8; |
a = a >> 8; |
if (subnet->prefixlen >= 16 ) |
if (subnet->prefixlen >= 16 ) |
p += sprintf(p, "%d.", a & 0xff); | p += sprintf(p, "%u.", a & 0xff); |
a = a >> 8; |
a = a >> 8; |
p += sprintf(p, "%d.in-addr.arpa", a & 0xff); | sprintf(p, "%u.in-addr.arpa", a & 0xff); |
|
|
} |
} |
#ifdef HAVE_IPV6 |
|
else |
else |
{ |
{ |
char *p = name; |
char *p = name; |
Line 534 size_t answer_auth(struct dns_header *header, char *li
|
Line 618 size_t answer_auth(struct dns_header *header, char *li
|
|
|
for (i = subnet->prefixlen-1; i >= 0; i -= 4) |
for (i = subnet->prefixlen-1; i >= 0; i -= 4) |
{ |
{ |
int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3]; | int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3]; |
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); |
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); |
} |
} |
p += sprintf(p, "ip6.arpa"); | sprintf(p, "ip6.arpa"); |
|
|
} |
} |
#endif |
|
} |
} |
|
|
/* handle NS and SOA in auth section or for explicit queries */ |
/* handle NS and SOA in auth section or for explicit queries */ |
Line 564 size_t answer_auth(struct dns_header *header, char *li
|
Line 647 size_t answer_auth(struct dns_header *header, char *li
|
{ |
{ |
struct name_list *secondary; |
struct name_list *secondary; |
|
|
newoffset = ansp - (unsigned char *)header; | /* Only include the machine running dnsmasq if it's acting as an auth server */ |
if (add_resource_record(header, limit, &trunc, -offset, &ansp, | if (daemon->authinterface) |
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) | |
{ |
{ |
if (offset == 0) | newoffset = ansp - (unsigned char *)header; |
offset = newoffset; | if (add_resource_record(header, limit, &trunc, -offset, &ansp, |
if (ns) | daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) |
anscount++; | { |
else | if (offset == 0) |
authcount++; | offset = newoffset; |
| if (ns) |
| anscount++; |
| else |
| authcount++; |
| } |
} |
} |
|
|
if (!subnet) |
if (!subnet) |
Line 677 size_t answer_auth(struct dns_header *header, char *li
|
Line 764 size_t answer_auth(struct dns_header *header, char *li
|
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) |
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) |
anscount++; |
anscount++; |
|
|
#ifdef HAVE_IPV6 |
|
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
if ((addrlist->flags & ADDRLIST_IPV6) && |
if ((addrlist->flags & ADDRLIST_IPV6) && |
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && |
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && |
add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) |
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) |
anscount++; |
anscount++; |
#endif |
|
|
|
/* restore config data */ |
/* restore config data */ |
if (cut) |
if (cut) |
Line 721 size_t answer_auth(struct dns_header *header, char *li
|
Line 806 size_t answer_auth(struct dns_header *header, char *li
|
{ |
{ |
char *cache_name = cache_get_name(crecp); |
char *cache_name = cache_get_name(crecp); |
if (!strchr(cache_name, '.') && |
if (!strchr(cache_name, '.') && |
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) | (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) && |
{ | add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
qtype = T_A; | daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, |
#ifdef HAVE_IPV6 | (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) |
if (crecp->flags & F_IPV6) | anscount++; |
qtype = T_AAAA; | |
#endif | |
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | |
daemon->auth_ttl, NULL, qtype, C_IN, | |
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) | |
anscount++; | |
} | |
} |
} |
|
|
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) |
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) |
{ |
{ |
strcpy(name, cache_get_name(crecp)); |
strcpy(name, cache_get_name(crecp)); |
if (in_zone(zone, name, &cut) && |
if (in_zone(zone, name, &cut) && |
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) | (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr)))) |
{ |
{ |
qtype = T_A; | if (cut) |
#ifdef HAVE_IPV6 | *cut = 0; |
if (crecp->flags & F_IPV6) | |
qtype = T_AAAA; | |
#endif | |
if (cut) | |
*cut = 0; | |
|
|
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
daemon->auth_ttl, NULL, qtype, C_IN, | daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, |
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) | (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) |
anscount++; | anscount++; |
} |
} |
} |
} |
} |
} |
Line 786 size_t answer_auth(struct dns_header *header, char *li
|
Line 859 size_t answer_auth(struct dns_header *header, char *li
|
header->hb4 &= ~HB4_RA; |
header->hb4 &= ~HB4_RA; |
} |
} |
|
|
/* authoritive */ | /* data is never DNSSEC signed. */ |
| header->hb4 &= ~HB4_AD; |
| |
| /* authoritative */ |
if (auth) |
if (auth) |
header->hb3 |= HB3_AA; |
header->hb3 |= HB3_AA; |
|
|
Line 798 size_t answer_auth(struct dns_header *header, char *li
|
Line 874 size_t answer_auth(struct dns_header *header, char *li
|
SET_RCODE(header, NXDOMAIN); |
SET_RCODE(header, NXDOMAIN); |
else |
else |
SET_RCODE(header, NOERROR); /* no error */ |
SET_RCODE(header, NOERROR); /* no error */ |
|
|
header->ancount = htons(anscount); |
header->ancount = htons(anscount); |
header->nscount = htons(authcount); |
header->nscount = htons(authcount); |
header->arcount = htons(0); |
header->arcount = htons(0); |
|
|
|
if (!local_query && out_of_zone) |
|
{ |
|
SET_RCODE(header, REFUSED); |
|
header->ancount = htons(0); |
|
header->nscount = htons(0); |
|
addr.log.rcode = REFUSED; |
|
addr.log.ede = EDE_NOT_AUTH; |
|
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0); |
|
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0); |
|
} |
|
|
|
/* Advertise our packet size limit in our reply */ |
|
if (have_pseudoheader) |
|
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); |
|
|
return ansp - (unsigned char *)header; |
return ansp - (unsigned char *)header; |
} |
} |
|
|
#endif |
#endif |
|
|
|
|
|
|