diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index 02e392aaf..b4e180882 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h @@ -74,8 +74,6 @@ struct server_config_t { #define SERVER_PORT 67 #endif -extern struct dhcpOfferedAddr *leases; - /*** leases.h ***/ @@ -92,9 +90,15 @@ struct dhcpOfferedAddr { * and optionally adjusted (current time subtracted) * if server_config.remaining = 1 */ leasetime_t expires; + uint8_t hostname[20]; /* (size is a multiply of 4) */ }; -struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) FAST_FUNC; +extern struct dhcpOfferedAddr *leases; + +struct dhcpOfferedAddr *add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname + ) FAST_FUNC; int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC; struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC; struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c index c0d515d28..1558f8848 100644 --- a/networking/udhcp/dumpleases.c +++ b/networking/udhcp/dumpleases.c @@ -47,8 +47,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) fd = xopen(file, O_RDONLY); - printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); - /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ + printf("Mac Address IP Address Host Name Expires %s\n", (opt & OPT_a) ? "at" : "in"); + /* "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */ + /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */ if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) return 0; @@ -64,7 +65,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) fmt = ":%02x"; } addr.s_addr = lease.yiaddr; - printf(" %-15s ", inet_ntoa(addr)); + /* actually, 15+1 and 19+1, +1 is a space between columns */ + /* lease.hostname is char[20] and is always NUL terminated */ + printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname); expires_abs = ntohl(lease.expires) + written_at; if (expires_abs <= curr) { puts("expired"); diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c index fb6fe01ae..a061a9c9b 100644 --- a/networking/udhcp/files.c +++ b/networking/udhcp/files.c @@ -420,7 +420,7 @@ void FAST_FUNC read_leases(const char *file) continue; /* NB: add_lease takes "relative time", IOW, * lease duration, not lease deadline. */ - if (!(add_lease(lease.chaddr, lease.yiaddr, expires))) { + if (!(add_lease(lease.chaddr, lease.yiaddr, expires, lease.hostname))) { bb_error_msg("too many leases while loading %s", file); break; } diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c index 3044c2040..d62f32471 100644 --- a/networking/udhcp/leases.c +++ b/networking/udhcp/leases.c @@ -48,9 +48,12 @@ static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) /* Add a lease into the table, clearing out any old ones */ -struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) +struct dhcpOfferedAddr* FAST_FUNC add_lease( + const uint8_t *chaddr, uint32_t yiaddr, + leasetime_t leasetime, uint8_t *hostname) { struct dhcpOfferedAddr *oldest; + uint8_t hostname_length; /* clean out any old ones */ clear_lease(chaddr, yiaddr); @@ -58,6 +61,19 @@ struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiad oldest = oldest_expired_lease(); if (oldest) { + oldest->hostname[0] = '\0'; + if (hostname) { + hostname_length = hostname[-1]; /* look at option size byte */ + if (hostname_length > sizeof(oldest->hostname)) + hostname_length = sizeof(oldest->hostname); + hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length); + /* sanitization (s/non-ACSII/^/g) */ + while (*hostname) { + if (*hostname < ' ' || *hostname > 126) + *hostname = '^'; + hostname++; + } + } memcpy(oldest->chaddr, chaddr, 16); oldest->yiaddr = yiaddr; oldest->expires = time(NULL) + leasetime; @@ -117,7 +133,7 @@ static int nobody_responds_to_arp(uint32_t addr) temp.s_addr = addr; bb_info_msg("%s belongs to someone, reserving it for %u seconds", inet_ntoa(temp), (unsigned)server_config.conflict_time); - add_lease(blank_chaddr, addr, server_config.conflict_time); + add_lease(blank_chaddr, addr, server_config.conflict_time, NULL); return 0; } diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c index 581a7b671..143a1fd1c 100644 --- a/networking/udhcp/options.c +++ b/networking/udhcp/options.c @@ -119,58 +119,61 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { }; -/* get an option with bounds checking (warning, not aligned). */ +/* get an option with bounds checking (warning, result is not aligned). */ uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) { - int i, length; uint8_t *optionptr; - int over = 0; - int curr = OPTION_FIELD; + int len; + int rem; + int overload = 0; + enum { + FILE_FIELD101 = FILE_FIELD * 0x101, + SNAME_FIELD101 = SNAME_FIELD * 0x101, + }; + /* option bytes: [code][len][data1][data2]..[dataLEN] */ optionptr = packet->options; - i = 0; - length = sizeof(packet->options); + rem = sizeof(packet->options); while (1) { - if (i >= length) { - bb_error_msg("bogus packet, option fields too long"); + if (rem <= 0) { + bb_error_msg("bogus packet, malformed option field"); return NULL; } - if (optionptr[i + OPT_CODE] == code) { - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - return optionptr + i + 2; + if (optionptr[OPT_CODE] == DHCP_PADDING) { + rem--; + optionptr++; + continue; } - switch (optionptr[i + OPT_CODE]) { - case DHCP_PADDING: - i++; - break; - case DHCP_OPTION_OVER: - if (i + 1 + optionptr[i + OPT_LEN] >= length) { - bb_error_msg("bogus packet, option fields too long"); - return NULL; - } - over = optionptr[i + 3]; - i += optionptr[OPT_LEN] + 2; - break; - case DHCP_END: - if (curr == OPTION_FIELD && (over & FILE_FIELD)) { + if (optionptr[OPT_CODE] == DHCP_END) { + if ((overload & FILE_FIELD101) == FILE_FIELD) { + /* can use packet->file, and didn't look at it yet */ + overload |= FILE_FIELD101; /* "we looked at it" */ optionptr = packet->file; - i = 0; - length = sizeof(packet->file); - curr = FILE_FIELD; - } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { + rem = sizeof(packet->file); + continue; + } + if ((overload & SNAME_FIELD101) == SNAME_FIELD) { + /* can use packet->sname, and didn't look at it yet */ + overload |= SNAME_FIELD101; /* "we looked at it" */ optionptr = packet->sname; - i = 0; - length = sizeof(packet->sname); - curr = SNAME_FIELD; - } else - return NULL; - break; - default: - i += optionptr[OPT_LEN + i] + 2; + rem = sizeof(packet->sname); + continue; + } + return NULL; } + len = 2 + optionptr[OPT_LEN]; + rem -= len; + if (rem < 0) + continue; /* complain and return NULL */ + + if (optionptr[OPT_CODE] == code) + return optionptr + OPT_DATA; + + if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { + overload |= optionptr[OPT_DATA]; + /* fall through */ + } + optionptr += len; } return NULL; } @@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr) int i = 0; while (optionptr[i] != DHCP_END) { - if (optionptr[i] == DHCP_PADDING) - i++; - else - i += optionptr[i + OPT_LEN] + 2; + if (optionptr[i] != DHCP_PADDING) + i += optionptr[i + OPT_LEN] + 1; + i++; } return i; } -/* add an option string to the options (an option string contains an option code, - * length, then data) */ +/* add an option string to the options */ +/* option bytes: [code][len][data1][data2]..[dataLEN] */ int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) { int end = end_option(optionptr); diff --git a/networking/udhcp/options.h b/networking/udhcp/options.h index d18a353d0..87440c30c 100644 --- a/networking/udhcp/options.h +++ b/networking/udhcp/options.h @@ -7,7 +7,7 @@ # pragma GCC visibility push(hidden) #endif -#define TYPE_MASK 0x0F +#define TYPE_MASK 0x0F enum { OPTION_IP = 1, @@ -24,8 +24,8 @@ enum { OPTION_S32 }; -#define OPTION_REQ 0x10 /* have the client request this option */ -#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ +#define OPTION_REQ 0x10 /* have the client request this option */ +#define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ /*****************************************************************/ /* Do not modify below here unless you know what you are doing!! */ @@ -34,67 +34,64 @@ enum { /* DHCP protocol -- see RFC 2131 */ #define DHCP_MAGIC 0x63825363 - /* DHCP option codes (partial list) */ -#define DHCP_PADDING 0x00 -#define DHCP_SUBNET 0x01 -#define DHCP_TIME_OFFSET 0x02 -#define DHCP_ROUTER 0x03 -#define DHCP_TIME_SERVER 0x04 -#define DHCP_NAME_SERVER 0x05 -#define DHCP_DNS_SERVER 0x06 -#define DHCP_LOG_SERVER 0x07 -#define DHCP_COOKIE_SERVER 0x08 -#define DHCP_LPR_SERVER 0x09 -#define DHCP_HOST_NAME 0x0c -#define DHCP_BOOT_SIZE 0x0d -#define DHCP_DOMAIN_NAME 0x0f -#define DHCP_SWAP_SERVER 0x10 -#define DHCP_ROOT_PATH 0x11 -#define DHCP_IP_TTL 0x17 -#define DHCP_MTU 0x1a -#define DHCP_BROADCAST 0x1c -#define DHCP_NTP_SERVER 0x2a -#define DHCP_WINS_SERVER 0x2c -#define DHCP_REQUESTED_IP 0x32 -#define DHCP_LEASE_TIME 0x33 -#define DHCP_OPTION_OVER 0x34 -#define DHCP_MESSAGE_TYPE 0x35 -#define DHCP_SERVER_ID 0x36 -#define DHCP_PARAM_REQ 0x37 -#define DHCP_MESSAGE 0x38 -#define DHCP_MAX_SIZE 0x39 -#define DHCP_T1 0x3a -#define DHCP_T2 0x3b -#define DHCP_VENDOR 0x3c -#define DHCP_CLIENT_ID 0x3d -#define DHCP_FQDN 0x51 -#define DHCP_END 0xFF +#define DHCP_PADDING 0x00 +#define DHCP_SUBNET 0x01 +#define DHCP_TIME_OFFSET 0x02 +#define DHCP_ROUTER 0x03 +#define DHCP_TIME_SERVER 0x04 +#define DHCP_NAME_SERVER 0x05 +#define DHCP_DNS_SERVER 0x06 +#define DHCP_LOG_SERVER 0x07 +#define DHCP_COOKIE_SERVER 0x08 +#define DHCP_LPR_SERVER 0x09 +#define DHCP_HOST_NAME 0x0c +#define DHCP_BOOT_SIZE 0x0d +#define DHCP_DOMAIN_NAME 0x0f +#define DHCP_SWAP_SERVER 0x10 +#define DHCP_ROOT_PATH 0x11 +#define DHCP_IP_TTL 0x17 +#define DHCP_MTU 0x1a +#define DHCP_BROADCAST 0x1c +#define DHCP_NTP_SERVER 0x2a +#define DHCP_WINS_SERVER 0x2c +#define DHCP_REQUESTED_IP 0x32 +#define DHCP_LEASE_TIME 0x33 +#define DHCP_OPTION_OVERLOAD 0x34 +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCP_SERVER_ID 0x36 +#define DHCP_PARAM_REQ 0x37 +#define DHCP_MESSAGE 0x38 +#define DHCP_MAX_SIZE 0x39 +#define DHCP_T1 0x3a +#define DHCP_T2 0x3b +#define DHCP_VENDOR 0x3c +#define DHCP_CLIENT_ID 0x3d +#define DHCP_FQDN 0x51 +#define DHCP_END 0xFF +/* Offsets in option byte sequence */ +#define OPT_CODE 0 +#define OPT_LEN 1 +#define OPT_DATA 2 +/* Bits in "overload" option */ +#define OPTION_FIELD 0 +#define FILE_FIELD 1 +#define SNAME_FIELD 2 +#define BOOTREQUEST 1 +#define BOOTREPLY 2 -#define BOOTREQUEST 1 -#define BOOTREPLY 2 +#define ETH_10MB 1 +#define ETH_10MB_LEN 6 -#define ETH_10MB 1 -#define ETH_10MB_LEN 6 - -#define DHCPDISCOVER 1 /* client -> server */ -#define DHCPOFFER 2 /* client <- server */ -#define DHCPREQUEST 3 /* client -> server */ -#define DHCPDECLINE 4 /* client -> server */ -#define DHCPACK 5 /* client <- server */ -#define DHCPNAK 6 /* client <- server */ -#define DHCPRELEASE 7 /* client -> server */ -#define DHCPINFORM 8 /* client -> server */ - -#define OPTION_FIELD 0 -#define FILE_FIELD 1 -#define SNAME_FIELD 2 - -/* miscellaneous defines */ -#define OPT_CODE 0 -#define OPT_LEN 1 -#define OPT_DATA 2 +#define DHCPDISCOVER 1 /* client -> server */ +#define DHCPOFFER 2 /* client <- server */ +#define DHCPREQUEST 3 /* client -> server */ +#define DHCPDECLINE 4 /* client -> server */ +#define DHCPACK 5 /* client <- server */ +#define DHCPNAK 6 /* client <- server */ +#define DHCPRELEASE 7 /* client -> server */ +#define DHCPINFORM 8 /* client -> server */ struct dhcp_option { uint8_t flags; diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c index 5d42a45db..3029b1367 100644 --- a/networking/udhcp/script.c +++ b/networking/udhcp/script.c @@ -135,7 +135,7 @@ static char **fill_envp(struct dhcpMessage *packet) char **envp, **curr; const char *opt_name; uint8_t *temp; - char over = 0; + uint8_t over = 0; if (packet) { for (i = 0; dhcp_options[i].code; i++) { @@ -147,7 +147,7 @@ static char **fill_envp(struct dhcpMessage *packet) } if (packet->siaddr) num_options++; - temp = get_option(packet, DHCP_OPTION_OVER); + temp = get_option(packet, DHCP_OPTION_OVERLOAD); if (temp) over = *temp; if (!(over & FILE_FIELD) && packet->file[0]) diff --git a/networking/udhcp/serverpacket.c b/networking/udhcp/serverpacket.c index afc0fb40d..8b0f1856b 100644 --- a/networking/udhcp/serverpacket.c +++ b/networking/udhcp/serverpacket.c @@ -105,7 +105,7 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) uint32_t req_align; uint32_t lease_time_aligned = server_config.lease; uint32_t static_lease_ip; - uint8_t *req, *lease_time; + uint8_t *req, *lease_time, *p_host_name; struct option_set *curr; struct in_addr addr; @@ -146,7 +146,8 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket) bb_error_msg("no IP addresses to give - OFFER abandoned"); return -1; } - if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time, p_host_name)) { bb_error_msg("lease pool is full - OFFER abandoned"); return -1; } @@ -201,6 +202,7 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) uint8_t *lease_time; uint32_t lease_time_aligned = server_config.lease; struct in_addr addr; + uint8_t *p_host_name; init_packet(&packet, oldpacket, DHCPACK); packet.yiaddr = yiaddr; @@ -232,7 +234,8 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) if (send_packet(&packet, 0) < 0) return -1; - add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned); + p_host_name = get_option(oldpacket, DHCP_HOST_NAME); + add_lease(packet.chaddr, packet.yiaddr, lease_time_aligned, p_host_name); if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) { /* rewrite the file with leases at every new acceptance */ write_leases();