From 1e4a9a7b61090043924f2aa9359dcbc9f5e11bfc Mon Sep 17 00:00:00 2001 From: Brandon Stepler Date: Mon, 25 Jan 2021 14:18:57 +0000 Subject: [PATCH] dhcpc6: support per-interface client DUIDs --- cfparse.y | 13 +++++++++++-- cftoken.l | 10 ++++++++++ config.c | 27 +++++++++++++++++++++++++++ config.h | 3 ++- dhcp6c.c | 11 ++++++++--- dhcp6c.conf.5 | 6 ++++++ 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/cfparse.y b/cfparse.y index 9e685f4..244987c 100644 --- a/cfparse.y +++ b/cfparse.y @@ -116,6 +116,7 @@ static void cleanup_cflist __P((struct cf_list *)); %token BCMCS_SERVERS BCMCS_NAME %token INFO_ONLY %token SCRIPT DELAYEDKEY +%token CLIENT_ID CLIENT_ID_DUID %token AUTHENTICATION PROTOCOL ALGORITHM DELAYED RECONFIG HMACMD5 MONOCOUNTER %token AUTHNAME RDM KEY %token KEYINFO REALM KEYID SECRET KEYNAME EXPIRE @@ -134,8 +135,8 @@ static void cleanup_cflist __P((struct cf_list *)); struct dhcp6_poolspec *pool; } -%type IFNAME HOSTNAME AUTHNAME KEYNAME DUID_ID STRING QSTRING IAID -%type POOLNAME PROFILENAME +%type IFNAME HOSTNAME CLIENT_ID_DUID AUTHNAME KEYNAME DUID_ID +%type STRING QSTRING IAID POOLNAME PROFILENAME %type NUMBER duration authproto authalg authrdm %type declaration declarations dhcpoption ifparam ifparams %type address_list address_list_ent dhcpoption_list @@ -639,6 +640,14 @@ dhcpoption: /* no value */ $$ = l; } + | CLIENT_ID CLIENT_ID_DUID + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_CLIENT_ID, NULL, NULL); + l->ptr = $2; + $$ = l; + } | AUTHENTICATION AUTHNAME { struct cf_list *l; diff --git a/cftoken.l b/cftoken.l index e266ac2..d7edd1f 100644 --- a/cftoken.l +++ b/cftoken.l @@ -119,6 +119,7 @@ ecl \} %s S_HOST %s S_DUID %s S_IA +%s S_CID %s S_AUTH %s S_KEY %s S_SECRET @@ -249,6 +250,15 @@ ecl \} /* duration */ infinity { DECHO; return (INFINITY); } + /* client-id option */ +client-id { DECHO; BEGIN S_CID; return (CLIENT_ID); } +{duid} { + DECHO; + yylval.str = strdup(yytext); + BEGIN S_CNF; + return (CLIENT_ID_DUID); +} + /* authentication option */ authentication { DECHO; BEGIN S_AUTH; return (AUTHENTICATION); } {string} { diff --git a/config.c b/config.c index 70f6287..0cbe631 100644 --- a/config.c +++ b/config.c @@ -100,6 +100,7 @@ struct dhcp6_ifconf { struct dhcp6_ifconf *next; char *ifname; + struct duid duid; /* configuration flags */ u_long send_flags; @@ -1366,6 +1367,7 @@ configure_commit() /* commit interface configuration */ for (ifp = dhcp6_if; ifp; ifp = ifp->next) { /* re-initialization */ + duidfree(&ifp->duid); ifp->send_flags = 0; ifp->allow_flags = 0; dhcp6_clear_list(&ifp->reqopt_list); @@ -1395,6 +1397,8 @@ configure_commit() } /* copy new configuration */ + ifp->duid = ifc->duid; + ifc->duid.duid_id = NULL; ifp->send_flags = ifc->send_flags; ifp->allow_flags = ifc->allow_flags; dhcp6_copy_list(&ifp->reqopt_list, &ifc->reqopt_list); @@ -1505,6 +1509,7 @@ clear_ifconf(iflist) ifc_next = ifc->next; free(ifc->ifname); + duidfree(&ifc->duid); dhcp6_clear_list(&ifc->reqopt_list); clear_iaconf(&ifc->iaconf_list); @@ -1635,6 +1640,28 @@ add_options(opcode, ifc, cfl0) return (-1); } break; + case DHCPOPT_CLIENT_ID: + if (opcode != DHCPOPTCODE_SEND) { + debug_printf(LOG_ERR, FNAME, + "invalid operation (%d) " + "for option type (%d)", + opcode, cfl->type); + return (-1); + } + if (ifc->duid.duid_id != NULL) { + debug_printf(LOG_ERR, FNAME, "%s:%d " + "client-id is doubly specified on %s", + configfilename, cfl->line, ifc->ifname); + return (-1); + } + if ((configure_duid((char *)cfl->ptr, + &ifc->duid)) != 0) { + debug_printf(LOG_ERR, FNAME, "%s:%d " + "failed to configure DUID for %s", + configfilename, cfl->line, ifc->ifname); + return (-1); + } + break; case DHCPOPT_AUTHINFO: if (opcode != DHCPOPTCODE_SEND) { debug_printf(LOG_ERR, FNAME, diff --git a/config.h b/config.h index 36a5aa3..cfcfdd5 100644 --- a/config.h +++ b/config.h @@ -69,6 +69,7 @@ struct dhcp6_if { u_int32_t linkid; /* to send link-local packets */ /* multiple global address configuration is not supported now */ struct in6_addr addr; /* global address */ + struct duid duid; /* configuration parameters */ u_long send_flags; @@ -267,7 +268,7 @@ enum { DECL_SEND, DECL_ALLOW, DECL_INFO_ONLY, DECL_REQUEST, DECL_DUID, DECL_ADDRESS, DECL_RANGE, DECL_ADDRESSPOOL, IFPARAM_SLA_ID, IFPARAM_SLA_LEN, IFPARAM_IFID, IFPARAM_IFID_RAND, - DHCPOPT_RAPID_COMMIT, DHCPOPT_AUTHINFO, + DHCPOPT_RAPID_COMMIT, DHCPOPT_CLIENT_ID, DHCPOPT_AUTHINFO, DHCPOPT_DNS, DHCPOPT_DNSNAME, DHCPOPT_IA_PD, DHCPOPT_IA_NA, DHCPOPT_NTP, DHCPOPT_REFRESHTIME, diff --git a/dhcp6c.c b/dhcp6c.c index 849835e..875a147 100644 --- a/dhcp6c.c +++ b/dhcp6c.c @@ -433,6 +433,11 @@ client6_start(ifp) } dhcp6_reset_timer(ev); + if (!ifp->duid.duid_id && duidcpy(&ifp->duid, &client_duid)) { + debug_printf(LOG_ERR, FNAME, "failed to copy client DUID"); + return (-1); + } + return (0); } @@ -1249,7 +1254,7 @@ client6_send(ev) } /* client ID */ - if (duidcpy(&optinfo.clientID, &client_duid)) { + if (duidcpy(&optinfo.clientID, &ifp->duid)) { debug_printf(LOG_ERR, FNAME, "failed to copy client ID"); goto end; } @@ -1533,7 +1538,7 @@ client6_recvadvert(ifp, dh6, len, optinfo) debug_printf(LOG_INFO, FNAME, "no client ID option"); return (-1); } - if (duidcmp(&optinfo->clientID, &client_duid)) { + if (duidcmp(&optinfo->clientID, &ifp->duid)) { debug_printf(LOG_INFO, FNAME, "client DUID mismatch"); return (-1); } @@ -1805,7 +1810,7 @@ client6_recvreply(ifp, dh6, len, optinfo) debug_printf(LOG_INFO, FNAME, "no client ID option"); return (-1); } - if (duidcmp(&optinfo->clientID, &client_duid)) { + if (duidcmp(&optinfo->clientID, &ifp->duid)) { debug_printf(LOG_INFO, FNAME, "client DUID mismatch"); return (-1); } diff --git a/dhcp6c.conf.5 b/dhcp6c.conf.5 index 5693fb8..589510a 100644 --- a/dhcp6c.conf.5 +++ b/dhcp6c.conf.5 @@ -139,6 +139,12 @@ An statement for .Ar authname must be provided. +.It Ic client-id Ar ID +means the client's DHCP unique identifier +.Pq DUID . +.Ar ID +is a colon-separated hexadecimal sequence where each separated part +must be composed of two hexadecimal values. .El .\" .Sh Interface statement -- 2.20.1