From a840884531df649aabc72debb2d6025dabe2abb3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 16 May 2019 11:18:49 +0200 Subject: [PATCH] udhcpd: support per-client hostnames in static leases function old new delta read_staticlease 222 299 +77 add_server_options 92 154 +62 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 139/0) Total: 139 bytes Signed-off-by: Denys Vlasenko --- examples/udhcp/udhcpd.conf | 9 +++-- networking/udhcp/dhcpd.c | 72 +++++++++++++++++++++++++++++++++----- networking/udhcp/dhcpd.h | 6 +--- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index bb8774e08..df1258aaf 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf @@ -44,7 +44,7 @@ interface eth0 #notify_file # default: no script #notify_file dumpleases # useful for debugging -# The following are bootp specific options +# The following are BOOTP specific options # next server to use in bootstrap #siaddr 192.168.0.22 # default: 0.0.0.0 (none) # tftp server name @@ -52,9 +52,14 @@ interface eth0 # tftp file to download (e.g. kernel image) #boot_file /var/nfs_root # default: none +# NOTE: "boot_file FILE" and "opt bootfile FILE" are conceptually the same, +# but "boot_file" goes into BOOTP-defined fixed-size field in the packet, +# whereas "opt bootfile" goes into DHCP option 0x43. +# Same for "sname HOST" and "opt tftp HOST". + # Static leases map #static_lease 00:60:08:11:CE:4E 192.168.0.54 -#static_lease 00:60:08:11:CE:3E 192.168.0.44 +#static_lease 00:60:08:11:CE:3E 192.168.0.44 optional_hostname # The remainder of options are DHCP options and can be specified with the # keyword 'opt' or 'option'. If an option can take multiple items, such diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index bf44320a1..f231e4001 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -48,14 +48,23 @@ #define g_leases ((struct dyn_lease*)ptr_to_globals) /* struct server_config_t server_config is in bb_common_bufsiz1 */ +struct static_lease { + struct static_lease *next; + uint32_t nip; + uint8_t mac[6]; + uint8_t opt[1]; +}; + /* Takes the address of the pointer to the static_leases linked list, * address to a 6 byte mac address, * 4 byte IP address */ static void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, - uint32_t nip) + uint32_t nip, + const char *opts) { struct static_lease *st_lease; + unsigned optlen; /* Find the tail of the list */ while ((st_lease = *st_lease_pp) != NULL) { @@ -63,10 +72,17 @@ static void add_static_lease(struct static_lease **st_lease_pp, } /* Add new node */ - *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease)); + optlen = (opts ? 1+1+strnlen(opts, 120) : 0); + *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease) + optlen); memcpy(st_lease->mac, mac, 6); st_lease->nip = nip; /*st_lease->next = NULL;*/ + if (optlen) { + st_lease->opt[OPT_CODE] = DHCP_HOST_NAME; + optlen -= 2; + st_lease->opt[OPT_LEN] = optlen; + memcpy(&st_lease->opt[OPT_DATA], opts, optlen); + } } /* Find static lease IP by mac */ @@ -344,6 +360,7 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg) char *line; char *mac_string; char *ip_string; + char *opts; struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */ uint32_t nip; @@ -358,7 +375,10 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg) if (!ip_string || !udhcp_str2nip(ip_string, &nip)) return 0; - add_static_lease(arg, (uint8_t*) &mac_bytes, nip); + opts = strtok_r(NULL, " \t", &line); + /* opts might be NULL, that's not an error */ + + add_static_lease(arg, (uint8_t*) &mac_bytes, nip, opts); log_static_leases(arg); @@ -626,14 +646,49 @@ static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacke */ static void add_server_options(struct dhcp_packet *packet) { - struct option_set *curr = server_config.options; + struct option_set *config_opts; + uint8_t *client_hostname_opt; - while (curr) { - if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) - udhcp_add_binary_option(packet, curr->data); - curr = curr->next; + client_hostname_opt = NULL; + if (packet->yiaddr) { /* if we aren't from send_inform()... */ + struct static_lease *st_lease = server_config.static_leases; + while (st_lease) { + if (st_lease->nip == packet->yiaddr) { + if (st_lease->opt[0] != 0) + client_hostname_opt = st_lease->opt; + break; + } + st_lease = st_lease->next; + } } + config_opts = server_config.options; + while (config_opts) { + if (config_opts->data[OPT_CODE] != DHCP_LEASE_TIME) { + /* ^^^^ + * DHCP_LEASE_TIME is already filled, or in case of + * send_inform(), should not be filled at all. + */ + if (config_opts->data[OPT_CODE] != DHCP_HOST_NAME + || !client_hostname_opt + ) { + /* Why "!client_hostname_opt": + * add hostname only if client has no hostname + * on its static lease line. + * (Not that "opt hostname HOST" + * makes much sense in udhcpd.conf, + * that'd give all clients the same hostname, + * but it's a valid configuration). + */ + udhcp_add_binary_option(packet, config_opts->data); + } + } + config_opts = config_opts->next; + } + + if (client_hostname_opt) + udhcp_add_binary_option(packet, client_hostname_opt); + packet->siaddr_nip = server_config.siaddr_nip; if (server_config.sname) @@ -753,7 +808,6 @@ static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) lease_time_sec = select_lease_time(oldpacket); udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); - add_server_options(&packet); addr.s_addr = yiaddr; diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index b8f96b029..5c3bf5147 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h @@ -15,11 +15,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN #define DHCPD_CONF_FILE "/etc/udhcpd.conf" -struct static_lease { - struct static_lease *next; - uint32_t nip; - uint8_t mac[6]; -}; +struct static_lease; struct server_config_t { char *interface; /* interface to use */