From: Ed Bardsley Date: Wed, 5 Aug 2015 20:17:18 +0000 (+0100) Subject: Enhance --add-subnet to allow arbitary subnet addresses. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a7369bef8abd241c3d85633fa9c870943f091e76;p=people%2Fms%2Fdnsmasq.git Enhance --add-subnet to allow arbitary subnet addresses. --- diff --git a/CHANGELOG b/CHANGELOG index 3f4026d..bbc2834 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ version 2.76 least, 0.0.0.0 accesses the local host, so could be targets for DNS rebinding. See RFC 5735 section 3 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 Fix reversion on 2.74 which caused 100% CPU use when a diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index c8913b5..a23c898 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -604,17 +604,27 @@ experimental. Also note that exposing MAC addresses in this way may have security and privacy implications. The warning about caching given for --add-subnet applies to --add-mac too. .TP -.B --add-subnet[[=],] -Add the subnet address of the requestor to the DNS queries which are -forwarded upstream. The amount of the address forwarded depends on the -prefix length parameter: 32 (128 for IPv6) forwards the whole address, -zero forwards none of it but still marks the request so that no -upstream nameserver will add client address information either. The -default is zero for both IPv4 and IPv6. Note that upstream nameservers -may be configured to return different results based on this -information, but the dnsmasq cache does not take account. If a dnsmasq -instance is configured such that different results may be encountered, -caching should be disabled. +.B --add-subnet[[=[/]][,[/]]] +Add a subnet address to the DNS queries which are forwarded +upstream. If an address is specified in the flag, it will be used, +otherwise, the address of the requestor will be used. The amount of +the address forwarded depends on the prefix length parameter: 32 (128 +for IPv6) forwards the whole address, zero forwards none of it but +still marks the request so that no upstream nameserver will add client +address information either. The default is zero for both IPv4 and +IPv6. Note that upstream nameservers may be configured to return +different results based on this information, but the dnsmasq cache +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 .B \-c, --cache-size= Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. diff --git a/src/dnsmasq.h b/src/dnsmasq.h index cf1a782..f42acdb 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -541,6 +541,13 @@ struct iname { struct iname *next; }; +/* subnet parameters from command line */ +struct mysubnet { + union mysockaddr addr; + int addr_used; + int mask; +}; + /* resolv-file parms from command-line */ struct resolvc { struct resolvc *next; @@ -935,9 +942,9 @@ extern struct daemon { struct auth_zone *auth_zones; struct interface_name *int_names; char *mxtarget; - int addr4_netmask; - int addr6_netmask; - char *lease_file; + struct mysubnet *add_subnet4; + struct mysubnet *add_subnet6; + char *lease_file; char *username, *groupname, *scriptuser; char *luascript; char *authserver, *hostmaster; diff --git a/src/option.c b/src/option.c index ecc2619..746cd11 100644 --- a/src/option.c +++ b/src/option.c @@ -445,7 +445,7 @@ static struct { { LOPT_PXE_SERV, ARG_DUP, "", gettext_noop("Boot service for PXE menu."), 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_SBNET, ARG_ONE, "[,]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL }, + { LOPT_ADD_SBNET, ARG_ONE, "[,]", 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_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 }, @@ -722,6 +722,20 @@ static void do_usage(void) #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) { 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 li = match_suffix->next; free(match_suffix->suffix); free(match_suffix); - } + } break; } @@ -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); if (arg) { + char *err, *end; comma = split(arg); - if (!atoi_check(arg, &daemon->addr4_netmask) || - (comma && !atoi_check(comma, &daemon->addr6_netmask))) - ret_err(gen_err); + + struct mysubnet* new = opt_malloc(sizeof(struct mysubnet)); + 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; diff --git a/src/rfc1035.c b/src/rfc1035.c index 29e9e65..6a51b30 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -629,26 +629,47 @@ struct subnet_opt { #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) { /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ int len; void *addrp; + int sa_family = source->sa.sa_family; #ifdef HAVE_IPV6 if (source->sa.sa_family == AF_INET6) { - opt->family = htons(2); - opt->source_netmask = daemon->addr6_netmask; - addrp = &source->in6.sin6_addr; + opt->source_netmask = daemon->add_subnet6->mask; + if (daemon->add_subnet6->addr_used) + { + 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 #endif { - opt->family = htons(1); - opt->source_netmask = daemon->addr4_netmask; - addrp = &source->in.sin_addr; + opt->source_netmask = daemon->add_subnet4->mask; + if (daemon->add_subnet4->addr_used) + { + 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; @@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source) 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; memcpy(opt->addr, addrp, len); if (opt->source_netmask & 7) @@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, return len; } -