Commit a7369bef authored by Ed Bardsley's avatar Ed Bardsley Committed by Simon Kelley

Enhance --add-subnet to allow arbitary subnet addresses.

parent d2aa7dfb
...@@ -4,6 +4,10 @@ version 2.76 ...@@ -4,6 +4,10 @@ version 2.76
least, 0.0.0.0 accesses the local host, so could least, 0.0.0.0 accesses the local host, so could
be targets for DNS rebinding. See RFC 5735 section 3 be targets for DNS rebinding. See RFC 5735 section 3
for details. Thanks to Stephen Röttger for the bug report. for details. Thanks to Stephen Röttger for the bug report.
Enhance --add-subnet to allow arbitrary subnet addresses.
Thanks to Ed Barsley for the patch.
version 2.75 version 2.75
Fix reversion on 2.74 which caused 100% CPU use when a Fix reversion on 2.74 which caused 100% CPU use when a
......
...@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC addresses in this way may ...@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC addresses in this way may
have security and privacy implications. The warning about caching have security and privacy implications. The warning about caching
given for --add-subnet applies to --add-mac too. given for --add-subnet applies to --add-mac too.
.TP .TP
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>] .B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
Add the subnet address of the requestor to the DNS queries which are Add a subnet address to the DNS queries which are forwarded
forwarded upstream. The amount of the address forwarded depends on the upstream. If an address is specified in the flag, it will be used,
prefix length parameter: 32 (128 for IPv6) forwards the whole address, otherwise, the address of the requestor will be used. The amount of
zero forwards none of it but still marks the request so that no the address forwarded depends on the prefix length parameter: 32 (128
upstream nameserver will add client address information either. The for IPv6) forwards the whole address, zero forwards none of it but
default is zero for both IPv4 and IPv6. Note that upstream nameservers still marks the request so that no upstream nameserver will add client
may be configured to return different results based on this address information either. The default is zero for both IPv4 and
information, but the dnsmasq cache does not take account. If a dnsmasq IPv6. Note that upstream nameservers may be configured to return
instance is configured such that different results may be encountered, different results based on this information, but the dnsmasq cache
caching should be disabled. does not take account. If a dnsmasq instance is configured such that
different results may be encountered, caching should be disabled.
For example,
.B --add-subnet=24,96
will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
.B --add-subnet=1.2.3.4/24
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
.TP .TP
.B \-c, --cache-size=<cachesize> .B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
......
...@@ -541,6 +541,13 @@ struct iname { ...@@ -541,6 +541,13 @@ struct iname {
struct iname *next; struct iname *next;
}; };
/* subnet parameters from command line */
struct mysubnet {
union mysockaddr addr;
int addr_used;
int mask;
};
/* resolv-file parms from command-line */ /* resolv-file parms from command-line */
struct resolvc { struct resolvc {
struct resolvc *next; struct resolvc *next;
...@@ -935,9 +942,9 @@ extern struct daemon { ...@@ -935,9 +942,9 @@ extern struct daemon {
struct auth_zone *auth_zones; struct auth_zone *auth_zones;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
int addr4_netmask; struct mysubnet *add_subnet4;
int addr6_netmask; struct mysubnet *add_subnet6;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
char *luascript; char *luascript;
char *authserver, *hostmaster; char *authserver, *hostmaster;
......
...@@ -445,7 +445,7 @@ static struct { ...@@ -445,7 +445,7 @@ static struct {
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL }, { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL }, { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
...@@ -722,6 +722,20 @@ static void do_usage(void) ...@@ -722,6 +722,20 @@ static void do_usage(void)
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0) #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
{
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
addr->sa.sa_family = AF_INET;
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
addr->sa.sa_family = AF_INET6;
#endif
else
return _("bad address");
return NULL;
}
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags) char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
{ {
int source_port = 0, serv_port = NAMESERVER_PORT; int source_port = 0, serv_port = NAMESERVER_PORT;
...@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
li = match_suffix->next; li = match_suffix->next;
free(match_suffix->suffix); free(match_suffix->suffix);
free(match_suffix); free(match_suffix);
} }
break; break;
} }
...@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
set_option_bool(OPT_CLIENT_SUBNET); set_option_bool(OPT_CLIENT_SUBNET);
if (arg) if (arg)
{ {
char *err, *end;
comma = split(arg); comma = split(arg);
if (!atoi_check(arg, &daemon->addr4_netmask) ||
(comma && !atoi_check(comma, &daemon->addr6_netmask))) struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
ret_err(gen_err); if ((end = split_chr(arg, '/')))
{
/* has subnet+len */
err = parse_mysockaddr(arg, &new->addr);
if (err)
ret_err(err);
if (!atoi_check(end, &new->mask))
ret_err(gen_err);
new->addr_used = 1;
}
else if (!atoi_check(arg, &new->mask))
ret_err(gen_err);
daemon->add_subnet4 = new;
new = opt_malloc(sizeof(struct mysubnet));
if (comma)
{
if ((end = split_chr(comma, '/')))
{
/* has subnet+len */
err = parse_mysockaddr(comma, &new->addr);
if (err)
ret_err(err);
if (!atoi_check(end, &new->mask))
ret_err(gen_err);
new->addr_used = 1;
}
else
{
if (!atoi_check(comma, &new->mask))
ret_err(gen_err);
}
}
daemon->add_subnet6 = new;
} }
break; break;
......
...@@ -629,26 +629,47 @@ struct subnet_opt { ...@@ -629,26 +629,47 @@ struct subnet_opt {
#endif #endif
}; };
static void *get_addrp(union mysockaddr *addr, const short family)
{
#ifdef HAVE_IPV6
if (family == AF_INET6)
return &addr->in6.sin6_addr;
#endif
return &addr->in.sin_addr;
}
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source) static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
{ {
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len; int len;
void *addrp; void *addrp;
int sa_family = source->sa.sa_family;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (source->sa.sa_family == AF_INET6) if (source->sa.sa_family == AF_INET6)
{ {
opt->family = htons(2); opt->source_netmask = daemon->add_subnet6->mask;
opt->source_netmask = daemon->addr6_netmask; if (daemon->add_subnet6->addr_used)
addrp = &source->in6.sin6_addr; {
sa_family = daemon->add_subnet6->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
}
else
addrp = &source->in6.sin6_addr;
} }
else else
#endif #endif
{ {
opt->family = htons(1); opt->source_netmask = daemon->add_subnet4->mask;
opt->source_netmask = daemon->addr4_netmask; if (daemon->add_subnet4->addr_used)
addrp = &source->in.sin_addr; {
sa_family = daemon->add_subnet4->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
}
else
addrp = &source->in.sin_addr;
} }
opt->scope_netmask = 0; opt->scope_netmask = 0;
...@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source) ...@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
if (opt->source_netmask != 0) if (opt->source_netmask != 0)
{ {
#ifdef HAVE_IPV6
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
#else
opt->family = htons(1);
#endif
len = ((opt->source_netmask - 1) >> 3) + 1; len = ((opt->source_netmask - 1) >> 3) + 1;
memcpy(opt->addr, addrp, len); memcpy(opt->addr, addrp, len);
if (opt->source_netmask & 7) if (opt->source_netmask & 7)
...@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
return len; return len;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment