version 1.1, 2013/07/29 19:37:40
|
version 1.1.1.2, 2014/06/15 16:31:38
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2014 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 subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) | static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u) |
{ |
{ |
struct subnet *subnet; | struct addrlist *subnet; |
|
|
for (subnet = zone->subnet; subnet; subnet = subnet->next) |
for (subnet = zone->subnet; subnet; subnet = subnet->next) |
{ |
{ |
if (subnet->is6 && (flag & F_IPV4)) | if (!(subnet->flags & ADDRLIST_IPV6)) |
continue; | |
| |
if (!subnet->is6) | |
{ |
{ |
struct in_addr addr = addr_u->addr.addr4; | struct in_addr netmask, addr = addr_u->addr.addr4; |
struct in_addr mask; | |
| if (!(flag & F_IPV4)) |
| continue; |
|
|
mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1)); | netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1)); |
|
|
if (is_same_net(addr, subnet->addr4, mask)) | if (is_same_net(addr, subnet->addr.addr.addr4, netmask)) |
return subnet; |
return subnet; |
} |
} |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen)) | else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen)) |
return subnet; |
return subnet; |
#endif |
#endif |
|
|
Line 46 static struct subnet *filter_zone(struct auth_zone *zo
|
Line 45 static struct subnet *filter_zone(struct auth_zone *zo
|
return NULL; |
return NULL; |
} |
} |
|
|
static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_addr *addr_u) | static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) |
{ |
{ |
#ifdef HAVE_DHCP6 | /* No zones specified, no filter */ |
struct dhcp_context *context; | if (!zone->subnet) |
| return 1; |
if (flag & F_IPV6) | |
for (context = daemon->dhcp6; context; context = context->next) | |
if ((context->flags & CONTEXT_CONSTRUCTED) && | |
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix)) | |
return 1; | |
#endif | |
|
|
return filter_zone(zone, flag, addr_u) != NULL; | return find_subnet(zone, flag, addr_u) != NULL; |
} |
} |
|
|
static int in_zone(struct auth_zone *zone, char *name, char **cut) | int in_zone(struct auth_zone *zone, char *name, char **cut) |
{ |
{ |
size_t namelen = strlen(name); |
size_t namelen = strlen(name); |
size_t domainlen = strlen(zone->domain); |
size_t domainlen = strlen(zone->domain); |
Line 88 static int in_zone(struct auth_zone *zone, char *name,
|
Line 81 static int in_zone(struct auth_zone *zone, char *name,
|
} |
} |
|
|
|
|
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr) | size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) |
{ |
{ |
char *name = daemon->namebuff; |
char *name = daemon->namebuff; |
unsigned char *p, *ansp; |
unsigned char *p, *ansp; |
Line 96 size_t answer_auth(struct dns_header *header, char *li
|
Line 89 size_t answer_auth(struct dns_header *header, char *li
|
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 = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; | int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; |
struct auth_zone *zone = NULL; |
struct auth_zone *zone = NULL; |
struct subnet *subnet = NULL; | struct addrlist *subnet = NULL; |
char *cut; |
char *cut; |
struct mx_srv_record *rec, *move, **up; |
struct mx_srv_record *rec, *move, **up; |
struct txt_record *txt; |
struct txt_record *txt; |
Line 109 size_t answer_auth(struct dns_header *header, char *li
|
Line 102 size_t answer_auth(struct dns_header *header, char *li
|
|
|
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) |
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) |
return 0; |
return 0; |
| |
/* determine end of question section (we put answers there) */ |
/* determine end of question section (we put answers there) */ |
if (!(ansp = skip_questions(header, qlen))) |
if (!(ansp = skip_questions(header, qlen))) |
return 0; /* bad packet */ |
return 0; /* bad packet */ |
Line 143 size_t answer_auth(struct dns_header *header, char *li
|
Line 136 size_t answer_auth(struct dns_header *header, char *li
|
if (!(flag = in_arpa_name_2_addr(name, &addr))) |
if (!(flag = in_arpa_name_2_addr(name, &addr))) |
continue; |
continue; |
|
|
for (zone = daemon->auth_zones; zone; zone = zone->next) | if (!local_query) |
if ((subnet = filter_zone(zone, flag, &addr))) | |
break; | |
| |
if (!zone) | |
{ |
{ |
auth = 0; | for (zone = daemon->auth_zones; zone; zone = zone->next) |
continue; | if ((subnet = find_subnet(zone, flag, &addr))) |
| break; |
| |
| if (!zone) |
| { |
| auth = 0; |
| continue; |
| } |
} |
} |
| |
| intr = NULL; |
| |
if (flag == F_IPV4) |
if (flag == F_IPV4) |
{ | for (intr = daemon->int_names; intr; intr = intr->next) |
for (intr = daemon->int_names; intr; intr = intr->next) | { |
{ | struct addrlist *addrlist; |
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr) | |
| for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
| if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr) |
break; |
break; |
else | |
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) | if (addrlist) |
intr = intr->next; | break; |
| else |
| while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
| intr = intr->next; |
| } |
| #ifdef HAVE_IPV6 |
| else if (flag == F_IPV6) |
| for (intr = daemon->int_names; intr; intr = intr->next) |
| { |
| struct addrlist *addrlist; |
| |
| for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
| if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6)) |
| break; |
| |
| if (addrlist) |
| break; |
| else |
| while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) |
| intr = intr->next; |
| } |
| #endif |
| |
| if (intr) |
| { |
| if (in_zone(zone, intr->name, NULL)) |
| { |
| found = 1; |
| log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); |
| if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
| daemon->auth_ttl, NULL, |
| T_PTR, C_IN, "d", intr->name)) |
| anscount++; |
} |
} |
|
|
if (intr) |
|
{ |
|
if (in_zone(zone, intr->name, NULL)) |
|
{ |
|
found = 1; |
|
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); |
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
|
daemon->auth_ttl, NULL, |
|
T_PTR, C_IN, "d", intr->name)) |
|
anscount++; |
|
} |
|
} |
|
} |
} |
| |
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag))) |
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag))) |
do { |
do { |
strcpy(name, cache_get_name(crecp)); |
strcpy(name, cache_get_name(crecp)); |
Line 212 size_t answer_auth(struct dns_header *header, char *li
|
Line 231 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) | if (found) |
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL); | nxdomain = 0; |
| else |
| log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL); |
|
|
continue; |
continue; |
} |
} |
Line 321 size_t answer_auth(struct dns_header *header, char *li
|
Line 342 size_t answer_auth(struct dns_header *header, char *li
|
anscount++; |
anscount++; |
} |
} |
} |
} |
| |
| if (qtype == T_A) |
| flag = F_IPV4; |
| |
| #ifdef HAVE_IPV6 |
| if (qtype == T_AAAA) |
| 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 (hostname_isequal(name, intr->name)) |
{ |
{ |
|
struct addrlist *addrlist; |
|
|
nxdomain = 0; |
nxdomain = 0; |
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1) | |
{ | if (flag) |
found = 1; | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL); | if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && |
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, | (local_query || filter_zone(zone, flag, &addrlist->addr))) |
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr)) | { |
anscount++; | found = 1; |
} | log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL); |
} | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
| daemon->auth_ttl, NULL, qtype, C_IN, |
| qtype == T_A ? "4" : "6", &addrlist->addr)) |
| anscount++; |
| } |
| } |
|
|
for (a = daemon->cnames; a; a = a->next) |
for (a = daemon->cnames; a; a = a->next) |
if (hostname_isequal(name, a->alias) ) |
if (hostname_isequal(name, a->alias) ) |
Line 349 size_t answer_auth(struct dns_header *header, char *li
|
Line 384 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
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, &nameoffset, |
T_CNAME, C_IN, "d", name)) |
T_CNAME, C_IN, "d", name)) |
anscount++; |
anscount++; |
|
|
goto cname_restart; |
goto cname_restart; |
} |
} |
|
|
if (qtype == T_A) |
|
flag = F_IPV4; |
|
|
|
#ifdef HAVE_IPV6 |
|
if (qtype == T_AAAA) |
|
flag = F_IPV6; |
|
#endif |
|
|
|
if (!cut) |
if (!cut) |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
|
|
if (qtype == T_SOA) |
if (qtype == T_SOA) |
{ |
{ |
soa = 1; /* inhibits auth section */ | auth = soa = 1; /* inhibits auth section */ |
found = 1; |
found = 1; |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); |
} |
} |
Line 403 size_t answer_auth(struct dns_header *header, char *li
|
Line 430 size_t answer_auth(struct dns_header *header, char *li
|
return 0; |
return 0; |
} |
} |
|
|
|
auth = 1; |
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; |
Line 412 size_t answer_auth(struct dns_header *header, char *li
|
Line 440 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
else if (qtype == T_NS) |
else if (qtype == T_NS) |
{ |
{ |
|
auth = 1; |
ns = 1; /* inhibits auth section */ |
ns = 1; /* inhibits auth section */ |
found = 1; |
found = 1; |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); |
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); |
Line 429 size_t answer_auth(struct dns_header *header, char *li
|
Line 458 size_t answer_auth(struct dns_header *header, char *li
|
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if ((crecp->flags & flag) && |
if ((crecp->flags & flag) && |
(filter_constructed_dhcp(zone, flag, &(crecp->addr.addr)))) | (local_query || filter_zone(zone, flag, &(crecp->addr.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.addr, record_source(crecp->uid)); |
Line 452 size_t answer_auth(struct dns_header *header, char *li
|
Line 481 size_t answer_auth(struct dns_header *header, char *li
|
do |
do |
{ |
{ |
nxdomain = 0; |
nxdomain = 0; |
if ((crecp->flags & flag) && filter_constructed_dhcp(zone, flag, &(crecp->addr.addr))) | if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) |
{ |
{ |
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); |
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); |
found = 1; |
found = 1; |
Line 483 size_t answer_auth(struct dns_header *header, char *li
|
Line 512 size_t answer_auth(struct dns_header *header, char *li
|
|
|
authname = name; |
authname = name; |
|
|
if (!subnet->is6) | if (!(subnet->flags & ADDRLIST_IPV6)) |
{ |
{ |
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8; | in_addr_t a = ntohl(subnet->addr.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, "%d.", a & 0xff); |
a = a >> 8; |
a = a >> 8; |
if (subnet->prefixlen != 8) | if (subnet->prefixlen >= 16 ) |
p += sprintf(p, "%d.", a & 0xff); |
p += sprintf(p, "%d.", a & 0xff); |
a = a >> 8; |
a = a >> 8; |
p += sprintf(p, "%d.in-addr.arpa", a & 0xff); |
p += sprintf(p, "%d.in-addr.arpa", a & 0xff); |
Line 505 size_t answer_auth(struct dns_header *header, char *li
|
Line 534 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->addr6)[i>>3]; | int dig = ((unsigned char *)&subnet->addr.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"); |
p += sprintf(p, "ip6.arpa"); |
Line 634 size_t answer_auth(struct dns_header *header, char *li
|
Line 663 size_t answer_auth(struct dns_header *header, char *li
|
} |
} |
|
|
for (intr = daemon->int_names; intr; intr = intr->next) |
for (intr = daemon->int_names; intr; intr = intr->next) |
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1) | if (in_zone(zone, intr->name, &cut)) |
{ |
{ |
|
struct addrlist *addrlist; |
|
|
if (cut) |
if (cut) |
*cut = 0; |
*cut = 0; |
|
|
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr)) | if (!(addrlist->flags & ADDRLIST_IPV6) && |
anscount++; | (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) && |
| add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
| daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) |
| anscount++; |
|
|
|
#ifdef HAVE_IPV6 |
|
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
|
if ((addrlist->flags & ADDRLIST_IPV6) && |
|
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && |
|
add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
|
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) |
|
anscount++; |
|
#endif |
|
|
/* restore config data */ |
/* restore config data */ |
if (cut) |
if (cut) |
*cut = '.'; |
*cut = '.'; |
} |
} |
| |
for (a = daemon->cnames; a; a = a->next) |
for (a = daemon->cnames; a; a = a->next) |
if (in_zone(zone, a->alias, &cut)) |
if (in_zone(zone, a->alias, &cut)) |
{ |
{ |
Line 677 size_t answer_auth(struct dns_header *header, char *li
|
Line 720 size_t answer_auth(struct dns_header *header, char *li
|
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN)) |
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN)) |
{ |
{ |
char *cache_name = cache_get_name(crecp); |
char *cache_name = cache_get_name(crecp); |
if (!strchr(cache_name, '.') && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))) | if (!strchr(cache_name, '.') && |
| (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) |
{ |
{ |
qtype = T_A; |
qtype = T_A; |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
Line 694 size_t answer_auth(struct dns_header *header, char *li
|
Line 738 size_t answer_auth(struct dns_header *header, char *li
|
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) && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))) | if (in_zone(zone, name, &cut) && |
| (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) |
{ |
{ |
qtype = T_A; |
qtype = T_A; |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
Line 729 size_t answer_auth(struct dns_header *header, char *li
|
Line 774 size_t answer_auth(struct dns_header *header, char *li
|
/* done all questions, set up header and return length of result */ |
/* done all questions, set up header and return length of result */ |
/* clear authoritative and truncated flags, set QR flag */ |
/* clear authoritative and truncated flags, set QR flag */ |
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR; |
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR; |
/* clear RA flag */ |
|
header->hb4 &= ~HB4_RA; |
|
|
|
|
if (local_query) |
|
{ |
|
/* set RA flag */ |
|
header->hb4 |= HB4_RA; |
|
} |
|
else |
|
{ |
|
/* clear RA flag */ |
|
header->hb4 &= ~HB4_RA; |
|
} |
|
|
/* authoritive */ |
/* authoritive */ |
if (auth) |
if (auth) |
header->hb3 |= HB3_AA; |
header->hb3 |= HB3_AA; |
Line 740 size_t answer_auth(struct dns_header *header, char *li
|
Line 794 size_t answer_auth(struct dns_header *header, char *li
|
if (trunc) |
if (trunc) |
header->hb3 |= HB3_TC; |
header->hb3 |= HB3_TC; |
|
|
if (anscount == 0 && auth && nxdomain) | if ((auth || local_query) && nxdomain) |
SET_RCODE(header, NXDOMAIN); |
SET_RCODE(header, NXDOMAIN); |
else |
else |
SET_RCODE(header, NOERROR); /* no error */ |
SET_RCODE(header, NOERROR); /* no error */ |