Compare commits

..
11 Commits
26 changed files with 6745 additions and 4455 deletions

No files matched your search

+6 -3
View File
@@ -33,7 +33,7 @@ version 2.66
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID, Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
DNSMASQ_REMOTE_ID variables to the environment of the DNSMASQ_REMOTE_ID variables to the environment of the
lease-change script (and the correponding Lua). These hold lease-change script (and the corresponding Lua). These hold
information inserted into the DHCP request by a DHCP relay information inserted into the DHCP request by a DHCP relay
agent. Thanks to Lakefield Communications for providing a agent. Thanks to Lakefield Communications for providing a
bounty for this addition. bounty for this addition.
@@ -47,9 +47,12 @@ version 2.66
patch. patch.
Don't erroneously reject some option names in --dhcp-match Don't erroneously reject some option names in --dhcp-match
options. Thnaks to Benedikt Hochstrasser for the bug report. 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
+2 -4
View File
@@ -33,10 +33,8 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
endif endif
endif endif
ifeq (,$(filter noipset,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_BUILD_ARCH_OS),linux) COPTS += -DNO_IPSET
COPTS += -DHAVE_IPSET
endif
endif endif
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
+24 -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
@@ -553,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
@@ -1753,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
@@ -1766,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 */
+2 -2
View File
@@ -135,12 +135,12 @@ 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 */
/* #define HAVE_IDN */ /* #define HAVE_IDN */
/* #define HAVE_CONNTRACK */ /* #define HAVE_CONNTRACK */
/* #define HAVE_IPSET */
/* Default locations for important system files. */ /* Default locations for important system files. */
@@ -327,7 +327,7 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_AUTH #undef HAVE_AUTH
#endif #endif
#ifndef HAVE_LINUX_NETWORK #if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
#undef HAVE_IPSET #undef HAVE_IPSET
#endif #endif
+1 -2
View File
@@ -714,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
+36 -29
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)
@@ -266,7 +266,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
} }
struct dhcp_context *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 iaid, 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.
@@ -286,7 +286,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
for (j = iaid, 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 | CONTEXT_USED)) if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
continue; continue;
@@ -296,7 +296,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
{ {
if (option_bool(OPT_CONSEC_ADDR)) if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */ /* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c); start = lease_find_max_addr6(c) + serial;
else else
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6))); start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
@@ -332,7 +332,8 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
/* 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,44 +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;
} }
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config) int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
{ {
/* expand wildcard on contructed contexts */ if (!config || !(config->flags & CONFIG_ADDR6))
if ((config->flags & CONFIG_WILDCARD) && return 0;
(context->flags & CONTEXT_CONSTRUCTED))
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
{ {
u64 addrpart = addr6part(&config->addr6); *addr = context->start6;
config->addr6 = context->start6; setaddr6part(addr, addr6part(&config->addr6));
setaddr6part(&config->addr6, addrpart); return 1;
}
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
{
*addr = config->addr6;
return 1; return 1;
} }
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
return 1;
return 0; return 0;
} }
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
{ {
for (; context; context = context->current) if (!(config->flags & CONFIG_ADDR6) ||
if (is_same_net6(addr, &context->start6, context->prefix)) (config->flags & CONFIG_WILDCARD))
return 1;
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0; return 0;
} }
@@ -521,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));
+13 -6
View File
@@ -684,7 +684,7 @@ struct cond_domain {
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
struct prefix_class { struct prefix_class {
int class; int class;
struct dhcp_netid netid; struct dhcp_netid tag;
struct prefix_class *next; struct prefix_class *next;
}; };
#endif #endif
@@ -721,7 +721,7 @@ 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 #define CONTEXT_USED 32768
struct ping_result { struct ping_result {
@@ -829,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 */
@@ -976,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);
@@ -1171,14 +1176,16 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
void dhcp6_init(void); void dhcp6_init(void);
void dhcp6_packet(time_t now); void dhcp6_packet(time_t now);
struct dhcp_context *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 iaid, 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,
int plain_range);
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,
+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;
+28 -6
View File
@@ -128,6 +128,9 @@ struct myoption {
#define LOPT_AUTHSFS 317 #define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318 #define LOPT_AUTHPEER 318
#define LOPT_IPSET 319 #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[] =
@@ -261,6 +264,9 @@ static const struct myoption opts[] =
{ "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 }, { "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 }
}; };
@@ -400,6 +406,9 @@ static struct {
{ 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 }, { 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 }
}; };
@@ -2366,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;
} }
@@ -2943,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);
+324 -116
View File
@@ -29,6 +29,9 @@ struct state {
char *iface_name; char *iface_name;
void *packet_options, *end; void *packet_options, *end;
struct dhcp_netid *tags, *context_tags; struct dhcp_netid *tags, *context_tags;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *send_prefix_class;
#endif
}; };
static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context, static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
@@ -45,11 +48,19 @@ static void get_context_tag(struct state *state, struct dhcp_context *context);
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option); static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
static int build_ia(struct state *state, int *t1cntr); static int build_ia(struct state *state, int *t1cntr);
static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz); static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
#endif
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr);
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
static int check_address(struct state *state, struct in6_addr *addr);
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now); unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now);
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now); static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
static int add_local_addrs(struct dhcp_context *context); static int add_local_addrs(struct dhcp_context *context);
struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context); struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context);
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2))) #define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2)) #define opt6_type(opt) (opt6_uint(opt, -4, 2))
@@ -204,6 +215,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
struct dhcp_context *context_tmp; struct dhcp_context *context_tmp;
unsigned int ignore = 0; unsigned int ignore = 0;
struct state state; struct state state;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *p;
int dump_all_prefix_classes = 0;
#endif
state.packet_options = inbuff + 4; state.packet_options = inbuff + 4;
state.end = inbuff + sz; state.end = inbuff + sz;
@@ -221,6 +236,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
state.client_hostname = NULL; state.client_hostname = NULL;
state.iface_name = iface_name; state.iface_name = iface_name;
state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */ state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
#ifdef OPTION6_PREFIX_CLASS
state.send_prefix_class = NULL;
#endif
/* set tag with name == interface */ /* set tag with name == interface */
iface_id.net = iface_name; iface_id.net = iface_name;
@@ -460,7 +478,32 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (have_config(config, CONFIG_DISABLE)) if (have_config(config, CONFIG_DISABLE))
ignore = 1; ignore = 1;
} }
#ifdef OPTION6_PREFIX_CLASS
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
{
void *oro;
if ((oro = opt6_find(state.packet_options, state.end, OPTION6_ORO, 0)))
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
{
dump_all_prefix_classes = 1;
break;
}
if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
/* Add the tags associated with prefix classes so we can use the DHCP ranges.
Not done for SOLICIT as we add them one-at-time. */
for (p = daemon->prefix_classes; p ; p = p->next)
{
p->tag.next = state.tags;
state.tags = &p->tag;
}
}
#endif
tagif = run_tag_if(state.tags); tagif = run_tag_if(state.tags);
/* if all the netids in the ignore list are present, ignore this client */ /* if all the netids in the ignore list are present, ignore this client */
@@ -495,8 +538,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
case DHCP6SOLICIT: case DHCP6SOLICIT:
{ {
void *rapid_commit = opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0); void *rapid_commit = opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0);
int used_config = 0, address_assigned = 0; int address_assigned = 0;
/* tags without all prefix-class tags */
struct dhcp_netid *solicit_tags = tagif;
struct dhcp_context *c;
if (rapid_commit) if (rapid_commit)
{ {
o = new_opt6(OPTION6_RAPID_COMMIT); o = new_opt6(OPTION6_RAPID_COMMIT);
@@ -506,111 +552,180 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set reply message type */ /* set reply message type */
*outmsgtypep = rapid_commit ? DHCP6REPLY : DHCP6ADVERTISE; *outmsgtypep = rapid_commit ? DHCP6REPLY : DHCP6ADVERTISE;
log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? "ignored" : NULL); log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
if (ignore) if (ignore)
return 0; return 0;
/* reset USED bits in leases */ /* reset USED bits in leases */
lease6_reset(); lease6_reset();
/* Can use configured address max once per prefix */
for (c = context; c; c = c->current)
c->flags &= ~CONTEXT_CONF_USED;
for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
{ {
void *ia_option, *ia_end; void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff; unsigned int min_time = 0xffffffff;
int t1cntr; int t1cntr;
int config_ok = 0; int ia_counter;
struct dhcp_context *c; /* set unless we're sending a particular prefix-class, when we
want only dhcp-ranges with the correct tags set and not those without any tags. */
int plain_range = 1;
u32 lease_time, requested_time; u32 lease_time, requested_time;
struct dhcp_lease *ltmp; struct dhcp_lease *ltmp;
struct in6_addr *req_addr; struct in6_addr *req_addr;
struct in6_addr addr; struct in6_addr addr;
if (!check_ia(&state, opt, &ia_end, &ia_option)) if (!check_ia(&state, opt, &ia_end, &ia_option))
continue; continue;
if (have_config(config, CONFIG_ADDR6))
{
struct dhcp_lease *config_lease = lease6_find_by_addr(&config->addr6, 128, 0);
config_ok = 1;
if (config_lease &&
(config_lease->clid_len != state.clid_len ||
memcmp(config_lease->clid, state.clid, state.clid_len) != 0 ||
config_lease->hwaddr_type != state.iaid))
config_ok = 0; /* configured address leased elsewhere */
}
/* reset USED bits in contexts - one address per prefix per IAID */ /* reset USED bits in contexts - one address per prefix per IAID */
for (c = context; c; c = c->current) for (c = context; c; c = c->current)
c->flags &= ~CONTEXT_USED; c->flags &= ~CONTEXT_USED;
#ifdef OPTION6_PREFIX_CLASS
if (daemon->prefix_classes && state.ia_type == OPTION6_IA_NA)
{
void *prefix_opt;
int prefix_class;
if (dump_all_prefix_classes)
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
plain_range = 0;
else
{
if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
{
prefix_class = opt6_uint(prefix_opt, 0, 2);
for (p = daemon->prefix_classes; p ; p = p->next)
if (p->class == prefix_class)
break;
if (!p)
my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
else
{
/* add tag to list, and exclude undecorated dhcp-ranges */
p->tag.next = state.tags;
solicit_tags = run_tag_if(&p->tag);
plain_range = 0;
state.send_prefix_class = p;
}
}
else
{
/* client didn't ask for a prefix class, lets see if we can find one. */
for (p = daemon->prefix_classes; p ; p = p->next)
{
p->tag.next = NULL;
if (match_netid(&p->tag, solicit_tags, 1))
break;
}
if (p)
{
plain_range = 0;
state.send_prefix_class = p;
}
}
if (p && option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state.xid, p->class, p->tag.net);
}
}
#endif
o = build_ia(&state, &t1cntr); o = build_ia(&state, &t1cntr);
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
req_addr = opt6_ptr(ia_option, 0); req_addr = opt6_ptr(ia_option, 0);
ltmp = lease6_find_by_addr(req_addr, 128, 0);
requested_time = opt6_uint(ia_option, 16, 4); requested_time = opt6_uint(ia_option, 16, 4);
if ((c = address6_valid(context, req_addr, tagif))) if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
{ {
lease_time = c->lease_time; lease_time = c->lease_time;
/* If the client asks for an address on the same network as a configured address, /* If the client asks for an address on the same network as a configured address,
offer the configured address instead, to make moving to newly-configured offer the configured address instead, to make moving to newly-configured
addresses automatic. */ addresses automatic. */
if (!used_config && config_ok && is_same_net6(req_addr, &config->addr6, c->prefix)) if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(&state, &addr))
{ {
req_addr = &config->addr6; req_addr = &addr;
used_config = 1; mark_config_used(c, &addr);
if (have_config(config, CONFIG_TIME)) if (have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
} }
else if (!(c = address6_available(context, req_addr, tagif))) else if (!(c = address6_available(context, req_addr, solicit_tags, plain_range)))
continue; /* not an address we're allowed */ continue; /* not an address we're allowed */
else if (ltmp && else if (!check_address(&state, req_addr))
(ltmp->clid_len != state.clid_len ||
memcmp(ltmp->clid, state.clid, state.clid_len) != 0 ||
ltmp->hwaddr_type != state.iaid))
continue; /* address leased elsewhere */ continue; /* address leased elsewhere */
/* add address to output packet */ /* add address to output packet */
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now); add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
} }
} }
/* Suggest configured address */ /* Suggest configured address(es) */
if (!used_config && config_ok && (c = address6_valid(context, &config->addr6, tagif))) for (c = context; c; c = c->current)
{ if (!(c->flags & CONTEXT_CONF_USED) &&
used_config = 1; match_netid(c->filter, solicit_tags, plain_range) &&
if (have_config(config, CONFIG_TIME)) config_valid(config, c, &addr) &&
lease_time = config->lease_time; check_address(&state, &addr))
/* add address to output packet */ {
add_address(&state, c, lease_time, requested_time, &min_time, &config->addr6, rapid_commit != NULL, now); mark_config_used(context, &addr);
get_context_tag(&state, c); if (have_config(config, CONFIG_TIME))
address_assigned = 1; lease_time = config->lease_time;
} else
lease_time = c->lease_time;
/* add address to output packet */
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, lease_time, requested_time, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr);
get_context_tag(&state, c);
address_assigned = 1;
}
/* return addresses for existing leases */ /* return addresses for existing leases */
ltmp = NULL; ltmp = NULL;
while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid))) while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid)))
{ {
req_addr = (struct in6_addr *)ltmp->hwaddr; req_addr = (struct in6_addr *)ltmp->hwaddr;
if ((c = address6_available(context, req_addr, tagif))) if ((c = address6_available(context, req_addr, solicit_tags, plain_range)))
{ {
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now); add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
} }
} }
/* Return addresses for all valid contexts which don't yet have one */ /* Return addresses for all valid contexts which don't yet have one */
while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, tagif, &addr))) while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, ia_counter, solicit_tags, plain_range, &addr)))
{ {
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now); add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
} }
@@ -623,7 +738,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS); put_opt6_short(DHCP6SUCCESS);
put_opt6_string("Oh hai from dnsmasq"); put_opt6_string(_("success"));
end_opt6(o1); end_opt6(o1);
/* If --dhcp-authoritative is set, we can tell client not to wait for /* If --dhcp-authoritative is set, we can tell client not to wait for
@@ -638,9 +753,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* no address, return error */ /* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS); put_opt6_short(DHCP6NOADDRS);
put_opt6_string("No addresses available"); put_opt6_string(_("no addresses available"));
end_opt6(o1); end_opt6(o1);
log6_packet(&state, "DHCPADVERTISE", NULL, _("No addresses available")); log6_packet(&state, "DHCPADVERTISE", NULL, _("no addresses available"));
} }
break; break;
@@ -653,7 +768,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set reply message type */ /* set reply message type */
*outmsgtypep = DHCP6REPLY; *outmsgtypep = DHCP6REPLY;
log6_packet(&state, "DHCPREQUEST", NULL, ignore ? "ignored" : NULL); log6_packet(&state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
if (ignore) if (ignore)
return 0; return 0;
@@ -675,24 +790,28 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
u32 requested_time = opt6_uint(ia_option, 16, 4); u32 requested_time = opt6_uint(ia_option, 16, 4);
struct dhcp_context *dynamic, *c; struct dhcp_context *dynamic, *c;
unsigned int lease_time; unsigned int lease_time;
struct in6_addr addr;
if ((dynamic = address6_available(context, req_addr, tagif)) || (c = address6_valid(context, req_addr, tagif))) int config_ok = 0;
if ((c = address6_valid(context, req_addr, tagif, 1)))
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
if ((dynamic = address6_available(context, req_addr, tagif, 1)) || c)
{ {
if (!dynamic && !(have_config(config, CONFIG_ADDR6) || !IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr))) if (!dynamic && !config_ok)
{ {
/* Static range, not configured. */ /* Static range, not configured. */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6UNSPEC); put_opt6_short(DHCP6UNSPEC);
put_opt6_string("Address unavailable"); put_opt6_string(_("address unavailable"));
end_opt6(o1); end_opt6(o1);
} }
else if (lease6_find_by_addr(req_addr, 128, 0) && else if (!check_address(&state, req_addr))
!lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.iaid, req_addr))
{ {
/* Address leased to another DUID/IAID */ /* Address leased to another DUID/IAID */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6UNSPEC); put_opt6_short(DHCP6UNSPEC);
put_opt6_string("Address in use"); put_opt6_string(_("address in use"));
end_opt6(o1); end_opt6(o1);
} }
else else
@@ -702,22 +821,24 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
lease_time = dynamic->lease_time; lease_time = dynamic->lease_time;
if (have_config(config, CONFIG_ADDR6) && if (config_ok && have_config(config, CONFIG_TIME))
IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr) &&
have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now); add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now);
get_context_tag(&state, dynamic); get_context_tag(&state, dynamic);
address_assigned = 1; address_assigned = 1;
} }
} }
else if (msg_type == DHCP6REQUEST) else
{ {
/* requested address not on the correct link */ /* requested address not on the correct link */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK); put_opt6_short(DHCP6NOTONLINK);
put_opt6_string("Not on link"); put_opt6_string(_("not on link"));
end_opt6(o1); end_opt6(o1);
} }
} }
@@ -730,7 +851,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS); put_opt6_short(DHCP6SUCCESS);
put_opt6_string("Oh hai from dnsmasq"); put_opt6_string(_("success"));
end_opt6(o1); end_opt6(o1);
} }
else else
@@ -738,9 +859,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* no address, return error */ /* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS); put_opt6_short(DHCP6NOADDRS);
put_opt6_string("No addresses available"); put_opt6_string(_("no addresses available"));
end_opt6(o1); end_opt6(o1);
log6_packet(&state, "DHCPREPLY", NULL, _("No addresses available")); log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available"));
} }
tagif = add_options(&state, fallback, context); tagif = add_options(&state, fallback, context);
@@ -772,14 +893,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
struct dhcp_lease *lease = NULL; struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 requested_time = opt6_uint(ia_option, 16, 4); u32 requested_time = opt6_uint(ia_option, 16, 4);
unsigned int lease_time; unsigned int preferred_time = 0; /* in case renewal inappropriate */
unsigned int valid_time = 0;
char *message = NULL;
struct dhcp_context *this_context; struct dhcp_context *this_context;
struct dhcp_config *valid_config = config;
/* don't use a config to set lease time if it specifies an address which isn't this. */
if (have_config(config, CONFIG_ADDR6) && !IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr))
valid_config = NULL;
if (!(lease = lease6_find(state.clid, state.clid_len, if (!(lease = lease6_find(state.clid, state.clid_len,
state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state.iaid, req_addr))) state.iaid, req_addr)))
@@ -790,48 +908,54 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
save_counter(iacntr); save_counter(iacntr);
t1cntr = 0; t1cntr = 0;
log6_packet(&state, "DHCPREPLY", req_addr, "lease not found"); log6_packet(&state, "DHCPREPLY", req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING); put_opt6_short(DHCP6NOBINDING);
put_opt6_string("No binding found"); put_opt6_string(_("no binding found"));
end_opt6(o1); end_opt6(o1);
break; break;
} }
if ((this_context = address6_available(context, req_addr, tagif)) || if ((this_context = address6_available(context, req_addr, tagif, 1)) ||
(this_context = address6_valid(context, req_addr, tagif))) (this_context = address6_valid(context, req_addr, tagif, 1)))
{ {
struct in6_addr addr;
unsigned int lease_time;
get_context_tag(&state, this_context); get_context_tag(&state, this_context);
lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time; if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
else
lease_time = this_context->lease_time;
if (requested_time < 120u ) calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time);
requested_time = 120u; /* sanity */
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = requested_time;
lease_set_expires(lease, lease_time, now); lease_set_expires(lease, valid_time, now);
if (state.ia_type == OPTION6_IA_NA && state.hostname) if (state.ia_type == OPTION6_IA_NA && state.hostname)
{ {
char *addr_domain = get_domain6(req_addr); char *addr_domain = get_domain6(req_addr);
if (!state.send_domain) if (!state.send_domain)
state.send_domain = addr_domain; state.send_domain = addr_domain;
lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain); lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain);
message = state.hostname;
} }
if (lease_time < min_time)
min_time = lease_time; if (preferred_time == 0)
message = _("deprecated");
} }
else
message = _("address invalid");
log6_packet(&state, "DHCPREPLY", req_addr, state.hostname); log6_packet(&state, "DHCPREPLY", req_addr, message);
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr)); put_opt6(req_addr, sizeof(*req_addr));
/* preferred lifetime */ put_opt6_long(preferred_time);
put_opt6_long(!this_context || (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time); put_opt6_long(valid_time);
put_opt6_long(!this_context ? 0 : lease_time); /* valid lifetime */
end_opt6(o1); end_opt6(o1);
} }
@@ -861,11 +985,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
if (!address6_available(context, req_addr, tagif)) if (!address6_available(context, req_addr, tagif, 1))
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK); put_opt6_short(DHCP6NOTONLINK);
put_opt6_string("Confirm failed"); put_opt6_string(_("confirm failed"));
end_opt6(o1); end_opt6(o1);
return 1; return 1;
} }
@@ -876,7 +1000,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS ); put_opt6_short(DHCP6SUCCESS );
put_opt6_string("All addresses still on link"); put_opt6_string(_("all addresses still on link"));
end_opt6(o1); end_opt6(o1);
break; break;
} }
@@ -890,7 +1014,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
context->netid.next = NULL; context->netid.next = NULL;
state.context_tags = &context->netid; state.context_tags = &context->netid;
} }
log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? "ignored" : state.hostname); log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname);
if (ignore) if (ignore)
return 0; return 0;
*outmsgtypep = DHCP6REPLY; *outmsgtypep = DHCP6REPLY;
@@ -946,7 +1070,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING); put_opt6_short(DHCP6NOBINDING);
put_opt6_string("No binding found"); put_opt6_string(_("no binding found"));
end_opt6(o1); end_opt6(o1);
end_opt6(o); end_opt6(o);
@@ -955,7 +1079,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS); put_opt6_short(DHCP6SUCCESS);
put_opt6_string("Release received"); put_opt6_string(_("release received"));
end_opt6(o1); end_opt6(o1);
break; break;
@@ -1023,7 +1147,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING); put_opt6_short(DHCP6NOBINDING);
put_opt6_string("No binding found"); put_opt6_string(_("no binding found"));
end_opt6(o1); end_opt6(o1);
end_opt6(o); end_opt6(o);
@@ -1257,6 +1381,22 @@ static void get_context_tag(struct state *state, struct dhcp_context *context)
} }
} }
} }
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
{
struct prefix_class *p;
struct dhcp_netid *t;
for (p = daemon->prefix_classes; p ; p = p->next)
for (t = context->filter; t; t = t->next)
if (strcmp(p->tag.net, t->net) == 0)
return p;
return NULL;
}
#endif
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option) static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
{ {
state->ia_type = opt6_type(opt); state->ia_type = opt6_type(opt);
@@ -1325,24 +1465,25 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now) unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
{ {
unsigned int valid_time = (context->valid < lease_time) ? context->valid : lease_time; unsigned int valid_time, preferred_time;
int o = new_opt6(OPTION6_IAADDR); int o = new_opt6(OPTION6_IAADDR);
struct dhcp_lease *lease; struct dhcp_lease *lease;
put_opt6(addr, sizeof(*addr)); calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time);
/* preferred lifetime */ put_opt6(addr, sizeof(*addr));
if (requested_time < 120u ) put_opt6_long(preferred_time);
requested_time = 120u; /* sanity */ put_opt6_long(valid_time);
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = requested_time; #ifdef OPTION6_PREFIX_CLASS
if (state->send_prefix_class)
if (lease_time < *min_time) {
*min_time = lease_time; int o1 = new_opt6(OPTION6_PREFIX_CLASS);
put_opt6_short(state->send_prefix_class->class);
end_opt6(o1);
}
#endif
put_opt6_long((context->preferred < lease_time) ? context->preferred : lease_time);
put_opt6_long(valid_time); /* valid lifetime */
end_opt6(o); end_opt6(o);
if (do_update) if (do_update)
@@ -1369,15 +1510,75 @@ static void add_address(struct state *state, struct dhcp_context *context, unsig
} }
} }
/* Mark that we have an address for this prefix. */
for (context = state->context; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix))
context->flags |= CONTEXT_USED;
log6_packet(state, do_update ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname); log6_packet(state, do_update ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
} }
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr)
{
/* Mark that we have an address for this prefix. */
#ifdef OPTION6_PREFIX_CLASS
for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix) &&
(!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
context->flags |= CONTEXT_USED;
#else
(void)state; /* warning */
for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix))
context->flags |= CONTEXT_USED;
#endif
}
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
{
for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix))
context->flags |= CONTEXT_CONF_USED;
}
/* make sure address not leased to another CLID/IAID */
static int check_address(struct state *state, struct in6_addr *addr)
{
struct dhcp_lease *lease;
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
return 1;
if (lease->clid_len != state->clid_len ||
memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
lease->hwaddr_type != state->iaid)
return 0;
return 1;
}
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time)
{
unsigned int preferred_time, valid_time;
if (requested_time < 120u )
requested_time = 120u; /* sanity */
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = requested_time;
valid_time = (context->valid < lease_time) ? context->valid : lease_time;
preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time;
if (context->flags & CONTEXT_DEPRECATE)
preferred_time = 0;
if (preferred_time != 0 && preferred_time < *min_time)
*min_time = preferred_time;
if (valid_time != 0 && valid_time < *min_time)
*min_time = valid_time;
*valid_timep = valid_time;
*preferred_timep = preferred_time;
}
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now) static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
{ {
struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0); struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
@@ -1506,6 +1707,13 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
optname = "iaaddr"; optname = "iaaddr";
ia_options = opt6_ptr(opt, 24); ia_options = opt6_ptr(opt, 24);
} }
#ifdef OPTION6_PREFIX_CLASS
else if (type == OPTION6_PREFIX_CLASS)
{
optname = "prefix-class";
sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
}
#endif
else if (type == OPTION6_STATUS_CODE) else if (type == OPTION6_STATUS_CODE)
{ {
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2)); int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
+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;
}