From 8b372704106bfa8777182db0264edc9fedb3dc0f Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 9 Mar 2012 17:45:10 +0000 Subject: [PATCH] Implement --dhcp-duid --- CHANGELOG | 2 ++ man/dnsmasq.8 | 10 ++++++++++ src/dhcp6.c | 27 ++++++++++++++++++++------- src/dnsmasq.c | 2 +- src/dnsmasq.h | 4 +++- src/lease.c | 19 ++++++++----------- src/option.c | 16 ++++++++++++++++ 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4174101..2d1bf3d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ version 2.61 Add ra-names DHCPv6 keyword which adds AAAA records for dual-stack hosts which get IPv6 addresses via SLAAC. + Add --dhcp-duid to allow DUID-EN uids to be used. + version 2.60 Fix compilation problem in Mac OS X Lion. Thanks to Olaf diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 3fd8c00..1a1ac54 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1042,6 +1042,16 @@ the tags used to determine them. .B \-l, --dhcp-leasefile= Use the specified file to store DHCP lease information. .TP +.B --dhcp-duid=, +(IPv6 only) Specify the server persistent UID which the DHCPv6 server +will use. This option is not normally required as dnsmasq creates a +DUID automatically when it is first needed. When given, this option +provides dnsmasq the data required to create a DUID-EN type DUID. Note +that once set, the DUID is stored in the lease database, so to change between DUID-EN and +automatically created DUIDs or vice-versa, the lease database must be +re-intialised. The enterprise-id is assigned by IANA, and the uid is a +string of hex octets unique to a particular device. +.TP .B \-6 --dhcp-script= Whenever a new DHCP lease is created, or an old one destroyed, the executable specified by this option is run. diff --git a/src/dhcp6.c b/src/dhcp6.c index e20ca36..154ff76 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -365,13 +365,26 @@ struct dhcp_config *find_config6(struct dhcp_config *configs, void make_duid(time_t now) { - /* rebase epoch to 1/1/2000 */ - time_t newnow = now - 946684800; - - iface_enumerate(AF_LOCAL, &newnow, make_duid1); - - if(!daemon->duid) - die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC); + if (daemon->duid_config) + { + unsigned char *p; + + daemon->duid = p = safe_malloc(daemon->duid_config_len + 6); + daemon->duid_len = daemon->duid_config_len + 6; + PUTSHORT(2, p); /* DUID_EN */ + PUTLONG(daemon->duid_enterprise, p); + memcpy(p, daemon->duid_config, daemon->duid_config_len); + } + else + { + /* rebase epoch to 1/1/2000 */ + time_t newnow = now - 946684800; + + iface_enumerate(AF_LOCAL, &newnow, make_duid1); + + if(!daemon->duid) + die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC); + } } static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm) diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 9ed6f3a..515f08f 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -196,7 +196,7 @@ int main (int argc, char **argv) #ifdef HAVE_DHCP /* after netlink_init */ if (daemon->dhcp || daemon->dhcp6) - lease_find_interfaces(); + lease_find_interfaces(now); #endif if (!enumerate_interfaces()) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 2ce22a7..d6179be 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -731,6 +731,8 @@ extern struct daemon { struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */ struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */ int tftp_unlimited; + unsigned int duid_enterprise, duid_config_len; + unsigned char *duid_config; /* globally used stuff for DNS */ char *packet; /* packet buffer */ @@ -956,7 +958,7 @@ void lease_prune(struct dhcp_lease *target, time_t now); void lease_update_from_configs(void); int do_script_run(time_t now); void rerun_scripts(void); -void lease_find_interfaces(void); +void lease_find_interfaces(time_t now); #ifdef HAVE_SCRIPT void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim); diff --git a/src/lease.c b/src/lease.c index e79b0db..3bc2222 100644 --- a/src/lease.c +++ b/src/lease.c @@ -175,16 +175,6 @@ void lease_init(time_t now) file_dirty = 0; lease_prune(NULL, now); dns_dirty = 1; - -#ifdef HAVE_DHCP6 - /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */ - if (!daemon->duid && daemon->dhcp6) - { - file_dirty = 1; - make_duid(now); - } -#endif - } void lease_update_from_configs(void) @@ -381,11 +371,18 @@ static int find_interface_v6(struct in6_addr *local, int prefix, we do DHCP transactions, but information about directly-connected subnets is useful from scrips and necessary for determining SLAAC addresses from start-time. */ -void lease_find_interfaces(void) +void lease_find_interfaces(time_t now) { iface_enumerate(AF_INET, NULL, find_interface_v4); #ifdef HAVE_DHCP6 iface_enumerate(AF_INET6, NULL, find_interface_v6); + + /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */ + if (!daemon->duid && daemon->dhcp6) + { + file_dirty = 1; + make_duid(now); + } #endif } diff --git a/src/option.c b/src/option.c index 13dc8bf..9259430 100644 --- a/src/option.c +++ b/src/option.c @@ -115,6 +115,7 @@ struct myoption { #define LOPT_FQDN 304 #define LOPT_LUASCRIPT 305 #define LOPT_RA 306 +#define LOPT_DUID 307 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -235,6 +236,7 @@ static const struct myoption opts[] = { "dhcp-client-update", 0, 0, LOPT_FQDN }, { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT }, { "enable-ra", 0, 0, LOPT_RA }, + { "dhcp-duid", 1, 0, LOPT_DUID }, { NULL, 0, 0, 0 } }; @@ -362,6 +364,7 @@ static struct { { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL }, { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL }, { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, + { LOPT_DUID, ARG_ONE, ",", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, { 0, 0, NULL, NULL, NULL } }; @@ -3047,6 +3050,19 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) break; #endif +#ifdef HAVE_DHCP6 + case LOPT_DUID: /* --dhcp-duid */ + if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise)) + problem = _("bad DUID"); + else + { + daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL); + daemon->duid_config = opt_malloc(daemon->duid_config_len); + memcpy(daemon->duid_config, comma, daemon->duid_config_len); + } + break; +#endif + case 'V': /* --alias */ { char *dash, *a[3] = { NULL, NULL, NULL };