Compare commits

...
25 Commits
Author SHA1 Message Date
Simon Kelley 8ac9787350 Fix lease time calculation when using DHCPv6 relay. 2013-03-30 21:34:19 +00:00
Simon Kelley 9f9bd08af8 Merged messages. 2013-03-22 15:11:53 +00:00
Simon Kelley 4c985dac39 Indentation. 2013-03-22 14:07:38 +00:00
Simon Kelley 3d77c0460d Typos in CHANGELOG 2013-03-22 10:03:50 +00:00
Simon Kelley 3ddad24608 Compile-in IPSET by default. 2013-03-21 17:56:06 +00:00
Simon Kelley 6e37ab595c Send prefix-class in DHCPREPLY as well as DHCPADVERTISE. 2013-03-19 20:50:11 +00:00
Simon Kelley a1a79edaea Bugfix for latest DHCPv6 update. 2013-03-15 21:19:57 +00:00
Simon Kelley 49333cbdbe Allow trailing '*' wildcard in interface names. 2013-03-15 20:30:51 +00:00
Simon Kelley de92b479d9 Make wildcard-configured addresses work on multiple networks. 2013-03-15 18:26:23 +00:00
Simon Kelley 0f128eb58c Clarifications for DNS-auth in man-page. 2013-03-11 21:21:35 +00:00
Simon Kelley c630924d66 Experimental support for DHCPv6 prefix-class option. 2013-03-07 20:59:28 +00:00
Simon Kelley ff59fc82b3 Split out context-marking from add_address. 2013-03-07 11:00:26 +00:00
Simon Kelley 52a1ae72f0 Another logic problem in refactor. 2013-03-06 22:43:26 +00:00
Simon Kelley 3a654c506f Respect difference between no IA_{TN}A and no IA_ADDR options. 2013-03-06 22:17:48 +00:00
Simon Kelley 2763d4b51a Fix unused variable warning. 2013-03-06 21:24:56 +00:00
Simon Kelley e28836bf45 Fix crash in DHCPv6 renew, introduced in refactor. 2013-03-06 21:22:22 +00:00
Simon Kelley a6ebfacf7b Massive refactor of stateful DHCPv6. Lease multiple prefixes per client. 2013-03-06 20:54:27 +00:00
Simon Kelley c7961075c4 Don't erroneously reject some option names in --dhcp-match 2013-02-28 15:17:58 +00:00
Simon Kelley ab6ede7e04 Handle EINTR return from sendto() in ipset.c 2013-02-23 19:22:37 +00:00
Simon Kelley b3538f1100 Add ipset.c to source files list in Android makefile. 2013-02-22 21:56:22 +00:00
Simon Kelley 3b323bda58 IPset support in debian build. 2013-02-22 21:55:29 +00:00
Jason A. Donenfeld 13d86c7372 Add --ipset option. 2013-02-22 21:44:08 +00:00
Simon Kelley 208fb610a6 Fix wrong DNSMASQ_LEASE_EXPIRES envar when luascript in use also. 2013-02-21 22:26:18 +00:00
Simon Kelley 4038ae2005 Fix crash in DHCPv6 information-request handler. 2013-02-19 16:47:07 +00:00
Simon Kelley dd1721c799 DHCPv4 relay-agent options exposed to DHCP-script. 2013-02-18 21:04:04 +00:00
38 changed files with 7768 additions and 5007 deletions

No files matched your search

+22 -1
View File
@@ -30,8 +30,29 @@ version 2.66
Don't send the default DHCP option advertising dnsmasq as Don't send the default DHCP option advertising dnsmasq as
the local DNS server if dnsmasq is configured to not act the local DNS server if dnsmasq is configured to not act
as DNS server, or it's configured to a non-standard port. as DNS server, or it's configured to a non-standard port.
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
DNSMASQ_REMOTE_ID variables to the environment of the
lease-change script (and the corresponding Lua). These hold
information inserted into the DHCP request by a DHCP relay
agent. Thanks to Lakefield Communications for providing a
bounty for this addition.
Fixed crash, introduced in 2.64, whilst handling DHCPv6
information-requests with some common configurations.
Thanks to Robert M. Albrecht for the bug report and
chasing the problem.
Add --ipset option. Thanks to Jason A. Donenfeld for the
patch.
Don't erroneously reject some option names in --dhcp-match
options. Thanks to Benedikt Hochstrasser for the bug report.
Allow a trailing '*' wildcard in all interface-name
configurations. Thanks to Christian Parpart for the patch.
version 2.65 version 2.65
Fix regression which broke forwarding of queries sent via Fix regression which broke forwarding of queries sent via
TCP which are not for A and AAAA and which were directed to TCP which are not for A and AAAA and which were directed to
+1 -1
View File
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h dns-protocol.h radv-protocol.h
+1 -1
View File
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \ rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c radv.c slaac.c auth.c ipset.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
+2 -1
View File
@@ -1,8 +1,9 @@
dnsmasq (2.66-1) unstable; urgency=low dnsmasq (2.66-1) unstable; urgency=low
* New upstream. * New upstream.
* Add support for noipset in DEB_BUILD_OPTIONS.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:58:41 +0000 -- Simon Kelley <simon@thekelleys.org.uk> Fri, 22 Feb 2013 21:52:13 +0000
dnsmasq (2.65-1) unstable; urgency=low dnsmasq (2.65-1) unstable; urgency=low
+1
View File
@@ -59,6 +59,7 @@ Notes on configuring dnsmasq as packaged for Debian.
noipv6 : omit IPv6 support. noipv6 : omit IPv6 support.
nodbus : omit DBus support. nodbus : omit DBus support.
noconntrack : omit connection tracking support. noconntrack : omit connection tracking support.
noipset : omit IPset support.
nortc : compile alternate mode suitable for systems without an RTC. nortc : compile alternate mode suitable for systems without an RTC.
noi18n : omit translations and internationalisation support. noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be noidn : omit international domain name support, must be
+4
View File
@@ -33,6 +33,10 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
endif endif
endif endif
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_IPSET
endif
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP6 COPTS += -DNO_DHCP6
endif endif
+4
View File
@@ -69,6 +69,10 @@
# --address (and --server) work with IPv6 addresses too. # --address (and --server) work with IPv6 addresses too.
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83 #address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
# Add the IPs of all queries to yahoo.com, google.com, and their
# subdomains to the vpn and search ipsets:
#ipset=/yahoo.com/google.com/vpn,search
# You can control how dnsmasq talks to a server: this forces # You can control how dnsmasq talks to a server: this forces
# queries to 10.1.2.3 to be routed via eth1 # queries to 10.1.2.3 to be routed via eth1
# server=10.1.2.3@eth1 # server=10.1.2.3@eth1
+33 -6
View File
@@ -171,7 +171,12 @@ options. IP alias interfaces (eg "eth1:0") cannot be used with
.B --interface .B --interface
or or
.B --except-interface .B --except-interface
options, use --listen-address instead. options, use --listen-address instead. A simple wildcard, consisting
of a trailing '*', can be used in
.B \--interface
and
.B \--except-interface
options.
.TP .TP
.B \-I, --except-interface=<interface name> .B \-I, --except-interface=<interface name>
Do not listen on the specified interface. Note that the order of Do not listen on the specified interface. Note that the order of
@@ -412,6 +417,12 @@ additional facility that /#/ matches any domain. Thus
answered from /etc/hosts or DHCP and not sent to an upstream answered from /etc/hosts or DHCP and not sent to an upstream
nameserver by a more specific --server directive. nameserver by a more specific --server directive.
.TP .TP
.B --ipset=/<domain>/[domain/]<ipset>[,<ipset>]
Places the resolved IP addresses of queries for the specified domains
in the specified netfilter ip sets. Domains and subdomains are matched
in the same way as --address. These ip sets must already exist. See
ipset(8) for more details.
.TP
.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>] .B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
Return an MX record named <mx name> pointing to the given hostname (if Return an MX record named <mx name> pointing to the given hostname (if
given), or given), or
@@ -547,7 +558,8 @@ Define a DNS zone for which dnsmasq acts as authoritative server. Locally define
will be served, except that A and AAAA records must be in one of the will be served, except that A and AAAA records must be in one of the
specified subnets, or in a subnet corresponding to a contructed DHCP specified subnets, or in a subnet corresponding to a contructed DHCP
range. The subnet(s) are also used to define in-addr.arpa and range. The subnet(s) are also used to define in-addr.arpa and
ipv6.arpa domains which are served for reverse-DNS queries. ipv6.arpa domains which are served for reverse-DNS queries. For IPv4
subnets, the prefix length is limited to the values 8, 16 or 24.
.TP .TP
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]] .B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
Specify fields in the SOA record associated with authoritative Specify fields in the SOA record associated with authoritative
@@ -1230,6 +1242,9 @@ For IPv4 only:
DNSMASQ_CLIENT_ID if the host provided a client-id. DNSMASQ_CLIENT_ID if the host provided a client-id.
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID if a
DHCP relay-agent added any of these options.
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS. If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
For IPv6 only: For IPv6 only:
@@ -1744,7 +1759,7 @@ we have
.fi .fi
.nf .nf
our.zone.com A 192.0.43.10 our.zone.com A 1.2.3.4
our.zone.com NS our.zone.com our.zone.com NS our.zone.com
.fi .fi
@@ -1757,11 +1772,23 @@ record. If the external address is static, this can be done with an
.B /etc/hosts .B /etc/hosts
entry or entry or
.B --host-record. .B --host-record.
If the external address is dynamic,
then it must be done using something like
.nf .nf
.B --interface-name=our.zone.com,eth0 .B auth-server=our.zone.com,eth0
.B host-record=our.zone.com,1.2.3.4
.B auth-zone=our.zone.com,1.2.3.0/24
.fi
If the external address is dynamic, the address
associated with our.zone.com must be derived from the address of the
relvant interface. This is done using
.B interface-name
Something like:
.nf
.B auth-server=our.zone.com,eth0
.B interface-name=our.zone.com,eth0
.B auth-zone=our.zone.com,1.2.3.0/24
.fi .fi
Our final configuration builds on that above, but also adds a Our final configuration builds on that above, but also adds a
+595 -413
View File
File diff suppressed because it is too large. Load diff
+651 -443
View File
File diff suppressed because it is too large. Load diff
+600 -405
View File
File diff suppressed because it is too large. Load diff
+654 -442
View File
File diff suppressed because it is too large. Load diff
+685 -461
View File
File diff suppressed because it is too large. Load diff
+600 -405
View File
File diff suppressed because it is too large. Load diff
+649 -442
View File
File diff suppressed because it is too large. Load diff
+594 -413
View File
File diff suppressed because it is too large. Load diff
+600 -405
View File
File diff suppressed because it is too large. Load diff
+649 -442
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -721,10 +721,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
daemon->soa_retry, daemon->soa_expiry, daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl)) daemon->auth_ttl))
anscount++; anscount++;
} }
} }
/* 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 */
+13 -1
View File
@@ -97,6 +97,10 @@ HAVE_CONNTRACK
a build-dependency on libnetfilter_conntrack, but the resulting binary will a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support. still run happily on a kernel without conntrack support.
HAVE_IPSET
define this to include the ability to selectively add resolved ip addresses
to given ipsets.
HAVE_AUTH HAVE_AUTH
define this to include the facility to act as an authoritative DNS define this to include the facility to act as an authoritative DNS
server for one or more zones. server for one or more zones.
@@ -131,6 +135,7 @@ RESOLVFILE
#define HAVE_TFTP #define HAVE_TFTP
#define HAVE_SCRIPT #define HAVE_SCRIPT
#define HAVE_AUTH #define HAVE_AUTH
#define HAVE_IPSET
/* #define HAVE_LUASCRIPT */ /* #define HAVE_LUASCRIPT */
/* #define HAVE_BROKEN_RTC */ /* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */ /* #define HAVE_DBUS */
@@ -138,7 +143,6 @@ RESOLVFILE
/* #define HAVE_CONNTRACK */ /* #define HAVE_CONNTRACK */
/* Default locations for important system files. */ /* Default locations for important system files. */
#ifndef LEASEFILE #ifndef LEASEFILE
@@ -323,6 +327,10 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_AUTH #undef HAVE_AUTH
#endif #endif
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
#undef HAVE_IPSET
#endif
/* Define a string indicating which options are in use. /* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */ DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
@@ -381,6 +389,10 @@ static char *compile_opts =
"no-" "no-"
#endif #endif
"conntrack " "conntrack "
#ifndef HAVE_IPSET
"no-"
#endif
"ipset "
#ifndef HAVE_AUTH #ifndef HAVE_AUTH
"no-" "no-"
#endif #endif
+5 -12
View File
@@ -518,8 +518,7 @@ u16 lookup_dhcp_opt(int prot, char *name)
t = opttab; t = opttab;
for (i = 0; t[i].name; i++) for (i = 0; t[i].name; i++)
if (!(t[i].size & OT_INTERNAL) && if (strcasecmp(t[i].name, name) == 0)
strcasecmp(t[i].name, name) == 0)
return t[i].val; return t[i].val;
return 0; return 0;
@@ -539,14 +538,9 @@ u16 lookup_dhcp_len(int prot, u16 val)
for (i = 0; t[i].name; i++) for (i = 0; t[i].name; i++)
if (val == t[i].val) if (val == t[i].val)
{ return t[i].size & ~OT_DEC;
if (t[i].size & OT_INTERNAL)
return 0; return 0;
return t[i].size & ~OT_DEC;
}
return 0;
} }
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len) char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
@@ -720,8 +714,7 @@ void log_context(int family, struct dhcp_context *context)
template = p; template = p;
p += sprintf(p, ", "); p += sprintf(p, ", ");
sprintf(p, "template for %s%s", context->template_interface, sprintf(p, "template for %s", context->template_interface);
(context->flags & CONTEXT_WILDCARD) ? "*" : "");
} }
#endif #endif
+1 -1
View File
@@ -252,7 +252,7 @@ void dhcp_packet(time_t now, int pxe_fd)
} }
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
/* unlinked contexts are marked by context->current == context */ /* unlinked contexts are marked by context->current == context */
+5
View File
@@ -59,6 +59,11 @@
#define OPTION6_SUBSCRIBER_ID 38 #define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39 #define OPTION6_FQDN 39
/* replace this with the real number when allocated.
defining this also enables the relevant code. */
/* #define OPTION6_PREFIX_CLASS 99 */
#define DHCP6SUCCESS 0 #define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1 #define DHCP6UNSPEC 1
#define DHCP6NOADDRS 2 #define DHCP6NOADDRS 2
+41 -62
View File
@@ -120,11 +120,11 @@ void dhcp6_packet(time_t now)
return; return;
for (tmp = daemon->if_except; tmp; tmp = tmp->next) for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
parm.current = NULL; parm.current = NULL;
@@ -153,7 +153,7 @@ void dhcp6_packet(time_t now)
{ {
for (tmp = daemon->if_names; tmp; tmp = tmp->next) for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break; break;
if (!tmp && !parm.addr_match) if (!tmp && !parm.addr_match)
@@ -265,8 +265,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return NULL; return NULL;
} }
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans) int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
{ {
/* Find a free address: exclude anything in use and anything allocated to /* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration. a particular hwaddr/clientid/hostname in our configuration.
@@ -283,12 +283,12 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
/* hash hwaddr: use the SDBM hashing algorithm. This works /* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */ for MAC addresses, let's see how it manages with client-ids! */
for (j = 0, i = 0; i < clid_len; i++) for (j = iaid, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j; j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= 1; pass++) for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current) for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS)) if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
continue; continue;
else if (!match_netid(c->filter, netids, pass)) else if (!match_netid(c->filter, netids, pass))
continue; continue;
@@ -298,7 +298,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
/* seed is largest extant lease addr in this context */ /* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial; start = lease_find_max_addr6(c) + serial;
else else
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6))); start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */ /* iterate until we find a free address. */
addr = start; addr = start;
@@ -315,7 +315,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{ {
*ans = c->start6; *ans = c->start6;
setaddr6part (ans, addr); setaddr6part (ans, addr);
return 1; return c;
} }
addr++; addr++;
@@ -325,14 +325,15 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
} while (addr != start); } while (addr != start);
} }
return 0; return 0;
} }
/* can dynamically allocate addr */ /* can dynamically allocate addr */
struct dhcp_context *address6_available(struct dhcp_context *context, struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids) struct dhcp_netid *netids,
int plain_range)
{ {
u64 start, end, addr = addr6part(taddr); u64 start, end, addr = addr6part(taddr);
struct dhcp_context *tmp; struct dhcp_context *tmp;
@@ -347,7 +348,7 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
is_same_net6(&tmp->end6, taddr, tmp->prefix) && is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
addr >= start && addr >= start &&
addr <= end && addr <= end &&
match_netid(tmp->filter, netids, 1)) match_netid(tmp->filter, netids, plain_range))
return tmp; return tmp;
} }
@@ -356,72 +357,52 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
/* address OK if configured */ /* address OK if configured */
struct dhcp_context *address6_valid(struct dhcp_context *context, struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids) struct dhcp_netid *netids,
int plain_range)
{ {
struct dhcp_context *tmp; struct dhcp_context *tmp;
for (tmp = context; tmp; tmp = tmp->current) for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) && if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
match_netid(tmp->filter, netids, 1)) match_netid(tmp->filter, netids, plain_range))
return tmp; return tmp;
return NULL; return NULL;
} }
struct dhcp_context *narrow_context6(struct dhcp_context *context, int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
struct in6_addr *taddr,
struct dhcp_netid *netids)
{ {
/* We start of with a set of possible contexts, all on the current physical interface. if (!config || !(config->flags & CONFIG_ADDR6))
These are chained on ->current. return 0;
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
if (!(tmp = address6_available(context, taddr, netids)) && if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
!(tmp = address6_valid(context, taddr, netids))) {
for (tmp = context; tmp; tmp = tmp->current) *addr = context->start6;
if (match_netid(tmp->filter, netids, 1) && setaddr6part(addr, addr6part(&config->addr6));
is_same_net6(taddr, &tmp->start6, tmp->prefix)) return 1;
break; }
/* Only one context allowed now */ if (is_same_net6(&context->start6, &config->addr6, context->prefix))
if (tmp) {
tmp->current = NULL; *addr = config->addr6;
return 1;
}
return tmp; return 0;
} }
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config) static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{ {
/* expand wildcard on contructed contexts */ if (!(config->flags & CONFIG_ADDR6) ||
if ((config->flags & CONFIG_WILDCARD) && (config->flags & CONFIG_WILDCARD))
(context->flags & CONTEXT_CONSTRUCTED))
{
u64 addrpart = addr6part(&config->addr6);
config->addr6 = context->start6;
setaddr6part(&config->addr6, addrpart);
return 1;
}
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
return 1; return 1;
return 0;
}
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
{
for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0; return 0;
} }
@@ -549,9 +530,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
} }
} }
else if (addr6part(local) == addr6part(&template->start6) && else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
strncmp(template->template_interface, ifrn_name, strlen(template->template_interface)) == 0 &&
(strlen(template->template_interface) == strlen(ifrn_name) || (template->flags & CONTEXT_WILDCARD)))
{ {
start6 = *local; start6 = *local;
setaddr6part(&start6, addr6part(&template->start6)); setaddr6part(&start6, addr6part(&template->start6));
+5
View File
@@ -213,6 +213,11 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_IPSET
if (daemon->ipsets)
ipset_init();
#endif
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
netlink_init(); netlink_init();
+39 -11
View File
@@ -430,6 +430,12 @@ struct server {
struct server *next; struct server *next;
}; };
struct ipsets {
char **sets;
char *domain;
struct ipsets *next;
};
struct irec { struct irec {
union mysockaddr addr; union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */ struct in_addr netmask; /* only valid for IPv4 */
@@ -675,6 +681,14 @@ struct cond_domain {
struct cond_domain *next; struct cond_domain *next;
}; };
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class {
int class;
struct dhcp_netid tag;
struct prefix_class *next;
};
#endif
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast; struct in_addr netmask, broadcast;
@@ -707,7 +721,8 @@ struct dhcp_context {
#define CONTEXT_CONSTRUCTED 2048 #define CONTEXT_CONSTRUCTED 2048
#define CONTEXT_GC 4096 #define CONTEXT_GC 4096
#define CONTEXT_RA 8192 #define CONTEXT_RA 8192
#define CONTEXT_WILDCARD 16384 #define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
@@ -779,6 +794,7 @@ extern struct daemon {
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers; struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
struct bogus_addr *bogus_addr; struct bogus_addr *bogus_addr;
struct server *servers; struct server *servers;
struct ipsets *ipsets;
int log_fac; /* log facility */ int log_fac; /* log facility */
char *log_file; /* optional log file */ char *log_file; /* optional log file */
int max_logs; /* queue limit */ int max_logs; /* queue limit */
@@ -813,6 +829,9 @@ extern struct daemon {
unsigned char *duid_config; unsigned char *duid_config;
char *dbus_name; char *dbus_name;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry; unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *prefix_classes;
#endif
/* globally used stuff for DNS */ /* globally used stuff for DNS */
char *packet; /* packet buffer */ char *packet; /* packet buffer */
@@ -903,7 +922,8 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags, struct all_addr *addrp, unsigned int flags,
unsigned long local_ttl); unsigned long local_ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
time_t now, int is_sign, int checkrebind, int checking_disabled); time_t now, char **ipsets, int is_sign, int checkrebind,
int checking_disabled);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now); struct in_addr local_addr, struct in_addr local_netmask, time_t now);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
@@ -959,6 +979,8 @@ char *print_mac(char *buff, unsigned char *mac, int len);
void bump_maxfd(int fd, int *max); void bump_maxfd(int fd, int *max);
int read_write(int fd, unsigned char *packet, int size, int rw); int read_write(int fd, unsigned char *packet, int size, int rw);
int wildcard_match(const char* wildcard, const char* match);
/* log.c */ /* log.c */
void die(char *message, char *arg1, int exit_code); void die(char *message, char *arg1, int exit_code);
int log_start(struct passwd *ent_pw, int errfd); int log_start(struct passwd *ent_pw, int errfd);
@@ -1047,7 +1069,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type); struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr); int lease_type, int iaid, struct in6_addr *addr);
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context); void lease6_reset(void);
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr); struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
u64 lease_find_max_addr6(struct dhcp_context *context); u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface); void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
@@ -1117,6 +1140,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif # endif
#endif #endif
/* ipset.c */
#ifdef HAVE_IPSET
void ipset_init(void);
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
#endif
/* helper.c */ /* helper.c */
#if defined(HAVE_SCRIPT) #if defined(HAVE_SCRIPT)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd); int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
@@ -1146,18 +1175,17 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
void dhcp6_init(void); void dhcp6_init(void);
void dhcp6_packet(time_t now); void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans); int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr); int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
struct dhcp_context *address6_available(struct dhcp_context *context, struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids,
int plain_range);
struct dhcp_context *address6_valid(struct dhcp_context *context, struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids,
struct dhcp_context *narrow_context6(struct dhcp_context *context, int plain_range);
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_config *find_config6(struct dhcp_config *configs, struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *duid, int duid_len, unsigned char *duid, int duid_len,
+20 -1
View File
@@ -439,9 +439,28 @@ static size_t process_reply(struct dns_header *header, time_t now,
struct server *server, size_t n, int check_rebind, int checking_disabled) struct server *server, size_t n, int check_rebind, int checking_disabled)
{ {
unsigned char *pheader, *sizep; unsigned char *pheader, *sizep;
char **sets = 0;
int munged = 0, is_sign; int munged = 0, is_sign;
size_t plen; size_t plen;
#ifdef HAVE_IPSET
/* Similar algorithm to search_servers. */
struct ipsets *ipset_pos;
unsigned int namelen = strlen(daemon->namebuff);
unsigned int matchlen = 0;
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
{
unsigned int domainlen = strlen(ipset_pos->domain);
char *matchstart = daemon->namebuff + namelen - domainlen;
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
domainlen >= matchlen) {
matchlen = domainlen;
sets = ipset_pos->sets;
}
}
#endif
/* If upstream is advertising a larger UDP packet size /* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ requests for the client. We can't do this for signed packets. */
@@ -494,7 +513,7 @@ static size_t process_reply(struct dns_header *header, time_t now,
SET_RCODE(header, NOERROR); SET_RCODE(header, NOERROR);
} }
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled)) if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, checking_disabled))
{ {
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff); my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
munged = 1; munged = 1;
+9 -8
View File
@@ -229,13 +229,6 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
} }
} }
/* expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u", data.length);
#else
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
#endif
/* supplied data may just exceed normal buffer (unlikely) */ /* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME && if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len))) !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
@@ -397,6 +390,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata_lua(buf, end, "cpewan_oui"); buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial"); buf = grab_extradata_lua(buf, end, "cpewan_serial");
buf = grab_extradata_lua(buf, end, "cpewan_class"); buf = grab_extradata_lua(buf, end, "cpewan_class");
buf = grab_extradata_lua(buf, end, "circuit_id");
buf = grab_extradata_lua(buf, end, "subscriber_id");
buf = grab_extradata_lua(buf, end, "remote_id");
} }
buf = grab_extradata_lua(buf, end, "tags"); buf = grab_extradata_lua(buf, end, "tags");
@@ -493,8 +489,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
my_setenv("DNSMASQ_INTERFACE", data.interface, &err); my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u", data.length);
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err); my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
#else #else
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif #endif
@@ -528,10 +526,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err); buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err); buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err); buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
} }
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err); buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
if (is6) if (is6)
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err); buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
else if (data.giaddr.s_addr != 0) else if (data.giaddr.s_addr != 0)
+205
View File
@@ -0,0 +1,205 @@
/* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
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
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_IPSET
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <linux/version.h>
#include <linux/netlink.h>
#include <linux/netfilter/nfnetlink.h>
#ifndef NFNL_SUBSYS_IPSET
#define NFNL_SUBSYS_IPSET 6
#define IPSET_ATTR_DATA 7
#define IPSET_ATTR_IP 1
#define IPSET_ATTR_IPADDR_IPV4 1
#define IPSET_ATTR_IPADDR_IPV6 2
#define IPSET_ATTR_PROTOCOL 1
#define IPSET_ATTR_SETNAME 2
#define IPSET_CMD_ADD 9
#define IPSET_CMD_DEL 10
#define IPSET_MAXNAMELEN 32
#define IPSET_PROTOCOL 6
#else
#include <linux/netfilter/ipset/ip_set.h>
#endif
/* data structure size in here is fixed */
#define BUFF_SZ 256
#define NL_ALIGN(len) (((len)+3) & ~(3))
static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
static int ipset_sock, old_kernel;
static char *buffer;
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
{
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len);
nlh->nlmsg_len += NL_ALIGN(payload_len);
}
void ipset_init(void)
{
struct utsname utsname;
int version;
char *split;
if (uname(&utsname) < 0)
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
split = strtok(utsname.release, ".");
version = (split ? atoi(split) : 0);
split = strtok(NULL, ".");
version = version * 256 + (split ? atoi(split) : 0);
split = strtok(NULL, ".");
version = version * 256 + (split ? atoi(split) : 0);
old_kernel = (version < KERNEL_VERSION(2,6,32));
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
return;
if (!old_kernel &&
(buffer = safe_malloc(BUFF_SZ)) &&
(ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
(bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
return;
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
}
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfg;
struct nlattr *nested[2];
uint8_t proto;
int addrsz = INADDRSZ;
ssize_t rc;
#ifdef HAVE_IPV6
if (af == AF_INET6)
addrsz = IN6ADDRSZ;
#endif
if (strlen(setname) >= IPSET_MAXNAMELEN)
{
errno = ENAMETOOLONG;
return -1;
}
memset(buffer, 0, sizeof(buffer));
nlh = (struct nlmsghdr *)buffer;
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
nlh->nlmsg_flags = NLM_F_REQUEST;
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len);
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg));
nfg->nfgen_family = af;
nfg->version = NFNETLINK_V0;
nfg->res_id = htons(0);
proto = IPSET_PROTOCOL;
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
add_attr(nlh,
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
addrsz, &ipaddr->addr);
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send());
return rc;
}
static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
{
socklen_t size;
struct ip_set_req_adt_get {
unsigned op;
unsigned version;
union {
char name[IPSET_MAXNAMELEN];
uint16_t index;
} set;
char typename[IPSET_MAXNAMELEN];
} req_adt_get;
struct ip_set_req_adt {
unsigned op;
uint16_t index;
uint32_t ip;
} req_adt;
if (strlen(setname) >= sizeof(req_adt_get.set.name))
{
errno = ENAMETOOLONG;
return -1;
}
req_adt_get.op = 0x10;
req_adt_get.version = 3;
strcpy(req_adt_get.set.name, setname);
size = sizeof(req_adt_get);
if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
return -1;
req_adt.op = remove ? 0x102 : 0x101;
req_adt.index = req_adt_get.set.index;
req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
return -1;
return 0;
}
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
{
int af = AF_INET;
#ifdef HAVE_IPV6
if (flags & F_IPV6)
{
af = AF_INET6;
/* old method only supports IPv4 */
if (old_kernel)
return -1;
}
#endif
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
}
#endif
+28 -17
View File
@@ -555,8 +555,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both /* find address for {CLID, IAID, address} */
set activates USED check */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr) int lease_type, int iaid, struct in6_addr *addr)
{ {
@@ -567,40 +566,52 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue; continue;
if (clid && addr && (lease->flags & LEASE_USED)) if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue; continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0) if ((clid_len != lease->clid_len ||
continue;
if (clid &&
(clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0)) memcmp(clid, lease->clid, clid_len) != 0))
continue; continue;
lease->flags |= LEASE_USED;
return lease; return lease;
} }
return NULL; return NULL;
} }
void lease6_filter(int lease_type, int iaid, struct dhcp_context *context) /* reset "USED flags */
void lease6_reset(void)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
lease->flags &= ~LEASE_USED;
}
/* enumerate all leases belonging to {CLID, IAID} */
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
{
struct dhcp_lease *lease;
if (!first)
first = leases;
for (lease = first; lease; lease = lease->next)
{ {
/* reset "USED flag */ if (lease->flags & LEASE_USED)
lease->flags &= ~LEASE_USED; continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue; continue;
/* leases on the wrong interface get filtered out here */ if ((clid_len != lease->clid_len ||
if (!is_addr_in_context6(context, (struct in6_addr *)&lease->hwaddr)) memcmp(clid, lease->clid, clid_len) != 0))
lease->flags |= LEASE_USED; continue;
return lease;
} }
return NULL;
} }
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr) struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
+3 -3
View File
@@ -123,7 +123,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
ret = 0; ret = 0;
for (tmp = daemon->if_names; tmp; tmp = tmp->next) for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0)) if (tmp->name && wildcard_match(tmp->name, name))
ret = tmp->used = 1; ret = tmp->used = 1;
if (addr) if (addr)
@@ -143,7 +143,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
} }
for (tmp = daemon->if_except; tmp; tmp = tmp->next) for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0)) if (tmp->name && wildcard_match(tmp->name, name))
ret = 0; ret = 0;
@@ -291,7 +291,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
} }
else else
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
{ {
tftp_ok = 0; tftp_ok = 0;
dhcp_ok = 0; dhcp_ok = 0;
+103 -6
View File
@@ -127,6 +127,10 @@ struct myoption {
#define LOPT_AUTHSOA 316 #define LOPT_AUTHSOA 316
#define LOPT_AUTHSFS 317 #define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318 #define LOPT_AUTHPEER 318
#define LOPT_IPSET 319
#ifdef OPTION6_PREFIX_CLASS
#define LOPT_PREF_CLSS 320
#endif
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -259,6 +263,10 @@ static const struct myoption opts[] =
{ "auth-soa", 1, 0, LOPT_AUTHSOA }, { "auth-soa", 1, 0, LOPT_AUTHSOA },
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
{ "auth-peer", 1, 0, LOPT_AUTHPEER }, { "auth-peer", 1, 0, LOPT_AUTHPEER },
{ "ipset", 1, 0, LOPT_IPSET },
#ifdef OPTION6_PREFIX_CLASS
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
#endif
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
@@ -397,6 +405,10 @@ static struct {
{ LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL }, { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
#ifdef OPTION6_PREFIX_CLASS
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
#endif
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
@@ -765,6 +777,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
new->opt = lookup_dhcp_opt(AF_INET, arg+7); new->opt = lookup_dhcp_opt(AF_INET, arg+7);
opt_len = lookup_dhcp_len(AF_INET, new->opt); opt_len = lookup_dhcp_len(AF_INET, new->opt);
/* option:<optname> must follow tag and vendor string. */ /* option:<optname> must follow tag and vendor string. */
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
new->opt = 0;
break; break;
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
@@ -783,6 +797,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{ {
new->opt = lookup_dhcp_opt(AF_INET6, arg+8); new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
opt_len = lookup_dhcp_len(AF_INET6, new->opt); opt_len = lookup_dhcp_len(AF_INET6, new->opt);
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
new->opt = 0;
} }
/* option6:<opt>|<optname> must follow tag and vendor string. */ /* option6:<opt>|<optname> must follow tag and vendor string. */
is6 = 1; is6 = 1;
@@ -2021,6 +2037,74 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->servers = newlist; daemon->servers = newlist;
break; break;
} }
case LOPT_IPSET: /* --ipset */
#ifndef HAVE_IPSET
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
break;
#else
{
struct ipsets ipsets_head;
struct ipsets *ipsets = &ipsets_head;
int size;
char *end;
char **sets, **sets_pos;
memset(ipsets, 0, sizeof(struct ipsets));
unhide_metas(arg);
if (arg && *arg == '/')
{
arg++;
while ((end = split_chr(arg, '/')))
{
char *domain = NULL;
/* elide leading dots - they are implied in the search algorithm */
while (*arg == '.')
arg++;
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0 || !*arg)
domain = "";
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
option = '?';
ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = domain;
arg = end;
}
}
else
{
ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = "";
}
if (!arg || !*arg)
{
option = '?';
break;
}
size = 2;
for (end = arg; *end; ++end)
if (*end == ',')
++size;
sets = sets_pos = opt_malloc(sizeof(char *) * size);
do {
end = split(arg);
*sets_pos++ = opt_string_alloc(arg);
arg = end;
} while (end);
*sets_pos = 0;
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
ipsets->next->sets = sets;
ipsets->next = daemon->ipsets;
daemon->ipsets = ipsets_head.next;
break;
}
#endif
case 'c': /* --cache-size */ case 'c': /* --cache-size */
{ {
@@ -2291,11 +2375,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->flags |= CONTEXT_DHCP; new->flags |= CONTEXT_DHCP;
else if (strstr(a[leasepos], "constructor:") == a[leasepos]) else if (strstr(a[leasepos], "constructor:") == a[leasepos])
{ {
if (a[leasepos][strlen(a[leasepos])-1] == '*')
{
a[leasepos][strlen(a[leasepos])-1] = 0;
new->flags |= CONTEXT_WILDCARD;
}
new->template_interface = opt_string_alloc(a[leasepos] + 12); new->template_interface = opt_string_alloc(a[leasepos] + 12);
new->flags |= CONTEXT_TEMPLATE; new->flags |= CONTEXT_TEMPLATE;
} }
@@ -2868,7 +2947,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
} }
break; break;
#ifdef OPTION6_PREFIX_CLASS
case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
{
struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
if (!(comma = split(arg)) ||
!atoi_check16(comma, &new->class))
ret_err(gen_err);
new->tag.net = opt_string_alloc(set_prefix(arg));
new->next = daemon->prefix_classes;
daemon->prefix_classes = new;
break;
}
#endif
case 'U': /* --dhcp-vendorclass */ case 'U': /* --dhcp-vendorclass */
case 'j': /* --dhcp-userclass */ case 'j': /* --dhcp-userclass */
case LOPT_CIRCUIT: /* --dhcp-circuitid */ case LOPT_CIRCUIT: /* --dhcp-circuitid */
+2 -2
View File
@@ -158,7 +158,7 @@ void icmp6_packet(time_t now)
return; return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0)) if (tmp->name && wildcard_match(tmp->name, interface))
return; return;
if (packet[1] != 0) if (packet[1] != 0)
@@ -533,7 +533,7 @@ time_t periodic_ra(time_t now)
{ {
struct iname *tmp; struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0)) if (tmp->name && wildcard_match(tmp->name, interface))
break; break;
if (!tmp) if (!tmp)
send_ra(now, param.iface, interface, NULL); send_ra(now, param.iface, interface, NULL);
+16 -2
View File
@@ -777,13 +777,18 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name)
expired and cleaned out that way. expired and cleaned out that way.
Return 1 if we reject an address because it look like part of dns-rebinding attack. */ Return 1 if we reject an address because it look like part of dns-rebinding attack. */
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now, int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
int is_sign, int check_rebind, int checking_disabled) char **ipsets, int is_sign, int check_rebind, int checking_disabled)
{ {
unsigned char *p, *p1, *endrr, *namep; unsigned char *p, *p1, *endrr, *namep;
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0; int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
unsigned long ttl = 0; unsigned long ttl = 0;
struct all_addr addr; struct all_addr addr;
#ifdef HAVE_IPSET
char **ipsets_cur;
#else
(void)ipsets; /* unused */
#endif
cache_start_insert(); cache_start_insert();
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */ /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
@@ -966,6 +971,15 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
(flags & F_IPV4) && (flags & F_IPV4) &&
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND))) private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1; return 1;
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
{
ipsets_cur = ipsets;
while (*ipsets_cur)
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
#endif
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD); newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
if (newc && cpp) if (newc && cpp)
+14 -1
View File
@@ -1256,7 +1256,20 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
add_extradata_opt(lease, oui); add_extradata_opt(lease, oui);
add_extradata_opt(lease, serial); add_extradata_opt(lease, serial);
add_extradata_opt(lease, class); add_extradata_opt(lease, class);
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
{
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
}
else
{
add_extradata_opt(lease, NULL);
add_extradata_opt(lease, NULL);
add_extradata_opt(lease, NULL);
}
/* space-concat tag set */ /* space-concat tag set */
if (!tagif_netid) if (!tagif_netid)
add_extradata_opt(lease, NULL); add_extradata_opt(lease, NULL);
+893 -595
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -209,7 +209,7 @@ void tftp_request(struct listener *listen, time_t now)
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
/* allowed interfaces are the same as for DHCP */ /* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0)) if (tmp->name && wildcard_match(tmp->name, name))
return; return;
#endif #endif
+17
View File
@@ -581,3 +581,20 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
return 1; return 1;
} }
/* Basically match a string value against a wildcard pattern. */
int wildcard_match(const char* wildcard, const char* match)
{
while (*wildcard && *match)
{
if (*wildcard == '*')
return 1;
if (*wildcard != *match)
return 0;
++wildcard;
++match;
}
return *wildcard == *match;
}