dhcpd: remember and record hostnames; optimize get_option dumpleases: show hostnames
No binary (build failed)
—
(log yok)
| @@ -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; | |
| @@ -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"); | |
| @@ -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; | |
| } | |
| @@ -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; | |
| } | |
| @@ -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); | |
| @@ -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 BOOTREQUEST 1 |
| - | #define BOOTREPLY 2 |
| - | |
| - | #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 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 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 */ |
| struct dhcp_option { | |
| uint8_t flags; | |
| @@ -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]) | |
| @@ -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(); | |