From: Roy Marples Date: Thu, 10 May 2007 16:08:49 +0000 (+0000) Subject: Add support for RFC 4361 X-Git-Tag: v3.2.3~264 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3d07f4c70c363a63fc549364b2f11f276f2056b;p=thirdparty%2Fdhcpcd.git Add support for RFC 4361 --- diff --git a/ChangeLog b/ChangeLog index 6334ed4c..301c268c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Use the DUID stored to create an RFC 4361 conformant client identifier +if none is specified instead of just using the MAC address. +Create a DUID-LLT according to RFC 3315 and store it in peristent file. config.h now has the compile time options, instead of being dotted around. Added -E option, which reads the last info file and uses the information there if we timeout and the lease is still valid, thanks to Roberto Angelino. diff --git a/Makefile b/Makefile index 4c3bbe31..ed783ca9 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ MAN8_TARGETS = dhcpcd.8 TARGET = $(SBIN_TARGETS) dhcpcd_H = version.h -dhcpcd_OBJS = arp.o client.o common.o configure.o dhcp.o dhcpcd.o \ +dhcpcd_OBJS = arp.o client.o common.o configure.o dhcp.o dhcpcd.o duid.o \ info.o interface.o logger.o signals.o socket.o # By default we don't need to link to anything diff --git a/pathnames.h b/config.h similarity index 69% rename from pathnames.h rename to config.h index c6c8f4da..df1ca3ad 100644 --- a/pathnames.h +++ b/config.h @@ -1,7 +1,7 @@ /* * dhcpcd - DHCP client daemon - - * Copyright 2005 - 2007 Roy Marples - * + * Copyright 2006-2007 Roy Marples + * * dhcpcd is an RFC2131 compliant DHCP client daemon. * * This is free software; you can redistribute it and/or modify it @@ -19,8 +19,27 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef PATHNAMES_H -#define PATHNAMES_H +#ifndef CONFIG_H +#define CONFIG_H + +/* You can enable/disable various chunks of optional code here. + * You would only do this to try and shrink the end binary if dhcpcd + * was running on a low memory device */ + +#define ENABLE_ARP +#define ENABLE_NTP +#define ENABLE_NIS +#define ENABLE_INFO +/* Define this to enable some compatability with 1.x and 2.x info files */ +// #define ENABLE_INFO_COMPAT + +/* We will auto create a DUID_LLT file if it doesn't exist. + * You can always create your own DUID file that just contains the + * hex string that represents the DUID. + * See RFC 3315 for details on this. */ +#define ENABLE_DUID + +/* Packname name and pathname definitions */ #define PACKAGE "dhcpcd" @@ -51,4 +70,6 @@ #define CONFIGDIR STATEDIR "/lib/" PACKAGE #define INFOFILE CONFIGDIR "/" PACKAGE "-%s.info" +#define DUIDFILE CONFIGDIR "/" PACKAGE ".duid" + #endif diff --git a/configure.c b/configure.c index 27567ce0..8690ea09 100644 --- a/configure.c +++ b/configure.c @@ -47,7 +47,6 @@ #endif #include "interface.h" #include "dhcpcd.h" -#include "pathnames.h" #include "logger.h" #include "socket.h" diff --git a/dhcp.c b/dhcp.c index 642e1d98..a0dade42 100644 --- a/dhcp.c +++ b/dhcp.c @@ -240,6 +240,24 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, *p++ = 0; /* string */ memcpy (p, options, l); p += l; +#ifdef ENABLE_DUID + } else if (iface->duid) { + *p++ = iface->duid_length + 5; + *p++ = 255; /* RFC 4361 */ + + /* IAID is 4 bytes, so if the interface name is 4 bytes then use it */ + if (strlen (iface->name) == 4) { + memcpy (p, iface->name, 4); + } else { + /* Name isn't 4 bytes, so use the index */ + ul = htonl (if_nametoindex (iface->name)); + memcpy (p, &ul, 4); + } + p += 4; + + memcpy (p, iface->duid, iface->duid_length); + p += iface->duid_length; +#endif } else { *p++ = iface->hwlen + 1; *p++ = iface->family; diff --git a/dhcpcd.8 b/dhcpcd.8 index 576da490..3ed93b4f 100644 --- a/dhcpcd.8 +++ b/dhcpcd.8 @@ -212,10 +212,12 @@ information is recorded in the file. .TP .BI \-I \ clientID -Specifies the client identifier string. +Specifies the client identifier string. If not specified then .B dhcpcd -uses the default client identifier (MAC address of the network -interface) if it is not specified. +will attempt to create a client identifier according to \fBRFC 4361\fR +and store the DUID part in /var/lib/dhcpcd/dhcpcd.duid, otherwise +.B dhcpcd +uses the MAC address of the network interface. .TP .BI \-M Prevents diff --git a/dhcpcd.c b/dhcpcd.c index 0ce089d7..3ac30448 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -38,16 +38,14 @@ #include #include +#include "config.h" #include "client.h" #include "dhcpcd.h" #include "dhcp.h" #include "interface.h" #include "logger.h" -#include "pathnames.h" #include "version.h" -#define PACKAGE "dhcpcd" - #define STRINGINT(_string, _int) { \ char *_tmp; \ long _number = strtol (_string, &_tmp, 0); \ diff --git a/duid.c b/duid.c new file mode 100644 index 00000000..0376d99c --- /dev/null +++ b/duid.c @@ -0,0 +1,120 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright 2006-2007 Roy Marples + * + * dhcpcd is an RFC2131 compliant DHCP client daemon. + * + * This 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "duid.h" +#include "logger.h" + +#ifdef ENABLE_DUID +#define DUID_LEN 130 + +#define THIRTY_YEARS_IN_SECONDS 946707779 + +void get_duid (interface_t *iface) +{ + FILE *fp; + uint16_t type = 0; + uint16_t hw = 0; + uint32_t ul; + time_t t; + unsigned char *p = iface->duid; + int x = 0; + + if (! iface) + return; + + /* Remove any existing */ + iface->duid[0] = '\0'; + iface->duid_length = 0; + + /* If we already have a DUID then use it as it's never supposed + * to change once we have one even if the interfaces do */ + if ((fp = fopen (DUIDFILE, "r"))) { + char *fduid; + char *fdp; + fduid = fdp = xmalloc ((sizeof (char *) * DUID_LEN * 2) + 1); + if (fscanf (fp, "%260s", fduid) == 1) { + char c[3]; + c[2] = '\0'; + while (*fdp) { + c[0] = *fdp++; + c[1] = *fdp++; + *p++ = (char) strtol (c, NULL, 16); + } + } + free (fduid); + iface->duid_length = p - iface->duid; + fclose (fp); + return; + } + + if (errno != ENOENT) { + logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); + return; + } + + /* No file? OK, lets make one based on our interface */ + type = htons (1); /* DUI-D-LLT */ + memcpy (p, &type, 2); + p += 2; + + hw = htons (iface->family); + memcpy (p, &hw, 2); + p += 2; + + /* time returns seconds from jan 1 1970, but DUID-LLT is + * seconds from jan 1 2000 modulo 2^32 */ + t = time (NULL) - THIRTY_YEARS_IN_SECONDS; + ul = htonl (t & 0xffffffff); + memcpy (p, &ul, 4); + p += 4; + + /* Finally, add the MAC address of the interface */ + memcpy (p, iface->hwaddr, iface->hwlen); + p += iface->hwlen; + + iface->duid_length = p - iface->duid; + + if (! (fp = fopen (DUIDFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); + else { + int i; + for (i = 0; i < iface->duid_length; i++) + x += fprintf (fp, "%.2X", iface->duid[i]); + fprintf (fp, "\n"); + fclose (fp); + } + + /* Failed to write the duid? scrub it, we cannot use it */ + if (x < 1) { + memset (iface->duid, 0, sizeof (iface->duid)); + iface->duid_length = 0; + } +} +#endif diff --git a/duid.h b/duid.h new file mode 100644 index 00000000..d12aacf1 --- /dev/null +++ b/duid.h @@ -0,0 +1,36 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright 2006-2007 Roy Marples + * + * dhcpcd is an RFC2131 compliant DHCP client daemon. + * + * This 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DUID_H +#define DUID_H + +#include "config.h" + +#ifdef ENABLE_DUID +#ifndef DUID_LENGTH_MAX +#define DUID_LENGTH_MAX 128 + 2 +#endif + +#include "interface.h" + +void get_duid (interface_t *iface); +#endif +#endif diff --git a/interface.c b/interface.c index cc3b48a1..3b05999f 100644 --- a/interface.c +++ b/interface.c @@ -58,11 +58,15 @@ #include #include +#include "config.h" #include "common.h" #include "dhcp.h" #include "interface.h" #include "logger.h" -#include "pathnames.h" + +#ifdef ENABLE_DUID +#include "duid.h" +#endif void free_address (address_t *addresses) { @@ -278,6 +282,13 @@ interface_t *read_interface (const char *ifname, int metric) logger (LOG_INFO, "hardware address = %s", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); +#ifdef ENABLE_DUID + get_duid (iface); + if (iface->duid_length > 0) + logger (LOG_INFO, "DUID = %s", + hwaddr_ntoa (iface->duid, iface->duid_length)); +#endif + /* 0 is a valid fd, so init to -1 */ iface->fd = -1; diff --git a/interface.h b/interface.h index e3b25cf7..a5064852 100644 --- a/interface.h +++ b/interface.h @@ -31,6 +31,13 @@ #include #include +#include "config.h" +#ifdef ENABLE_DUID +#ifndef DUID_LENGTH_MAX +#define DUID_LENGTH_MAX 128 + 2 +#endif +#endif + #define EUI64_ADDR_LEN 8 #define INFINIBAND_ADDR_LEN 20 @@ -82,6 +89,11 @@ typedef struct interface_t route_t *previous_routes; long start_uptime; + +#ifdef ENABLE_DUID + unsigned char duid[DUID_LENGTH_MAX]; + int duid_length; +#endif } interface_t; void free_address (address_t *addresses);