dhcpd: remember and record hostnames; optimize get_option

dumpleases: show hostnames

function                                             old     new   delta
add_lease                                            230     292     +62
send_offer                                           403     421     +18
send_ACK                                             232     249     +17
read_leases                                          249     258      +9
dumpleases_main                                      604     609      +5
nobody_responds_to_arp                                84      86      +2
udhcp_end_option                                      32      30      -2
udhcp_get_option                                     222     171     -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/2 up/down: 113/-53)            Total: 60 bytes
This commit is contained in:
Denis Vlasenko 2009-04-01 12:36:09 +00:00
parent 3266aa9ec2
commit bd79c3d337
8 changed files with 145 additions and 120 deletions

View File

@ -74,8 +74,6 @@ struct server_config_t {
#define SERVER_PORT 67 #define SERVER_PORT 67
#endif #endif
extern struct dhcpOfferedAddr *leases;
/*** leases.h ***/ /*** leases.h ***/
@ -92,9 +90,15 @@ struct dhcpOfferedAddr {
* and optionally adjusted (current time subtracted) * and optionally adjusted (current time subtracted)
* if server_config.remaining = 1 */ * if server_config.remaining = 1 */
leasetime_t expires; 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; 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_chaddr(const uint8_t *chaddr) FAST_FUNC;
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC; struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;

View File

@ -47,8 +47,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv)
fd = xopen(file, O_RDONLY); fd = xopen(file, O_RDONLY);
printf("Mac Address IP-Address Expires %s\n", (opt & OPT_a) ? "at" : "in"); 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 Wed Jun 30 21:49:08 1993" */ /* "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)) if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
return 0; return 0;
@ -64,7 +65,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv)
fmt = ":%02x"; fmt = ":%02x";
} }
addr.s_addr = lease.yiaddr; 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; expires_abs = ntohl(lease.expires) + written_at;
if (expires_abs <= curr) { if (expires_abs <= curr) {
puts("expired"); puts("expired");

View File

@ -420,7 +420,7 @@ void FAST_FUNC read_leases(const char *file)
continue; continue;
/* NB: add_lease takes "relative time", IOW, /* NB: add_lease takes "relative time", IOW,
* lease duration, not lease deadline. */ * 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); bb_error_msg("too many leases while loading %s", file);
break; break;
} }

View File

@ -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 */ /* 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; struct dhcpOfferedAddr *oldest;
uint8_t hostname_length;
/* clean out any old ones */ /* clean out any old ones */
clear_lease(chaddr, yiaddr); 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(); oldest = oldest_expired_lease();
if (oldest) { 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); memcpy(oldest->chaddr, chaddr, 16);
oldest->yiaddr = yiaddr; oldest->yiaddr = yiaddr;
oldest->expires = time(NULL) + leasetime; oldest->expires = time(NULL) + leasetime;
@ -117,7 +133,7 @@ static int nobody_responds_to_arp(uint32_t addr)
temp.s_addr = addr; temp.s_addr = addr;
bb_info_msg("%s belongs to someone, reserving it for %u seconds", bb_info_msg("%s belongs to someone, reserving it for %u seconds",
inet_ntoa(temp), (unsigned)server_config.conflict_time); 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; return 0;
} }

View File

@ -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) uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
{ {
int i, length;
uint8_t *optionptr; uint8_t *optionptr;
int over = 0; int len;
int curr = OPTION_FIELD; 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; optionptr = packet->options;
i = 0; rem = sizeof(packet->options);
length = sizeof(packet->options);
while (1) { while (1) {
if (i >= length) { if (rem <= 0) {
bb_error_msg("bogus packet, option fields too long"); bb_error_msg("bogus packet, malformed option field");
return NULL; return NULL;
} }
if (optionptr[i + OPT_CODE] == code) { if (optionptr[OPT_CODE] == DHCP_PADDING) {
if (i + 1 + optionptr[i + OPT_LEN] >= length) { rem--;
bb_error_msg("bogus packet, option fields too long"); optionptr++;
return NULL; continue;
}
return optionptr + i + 2;
} }
switch (optionptr[i + OPT_CODE]) { if (optionptr[OPT_CODE] == DHCP_END) {
case DHCP_PADDING: if ((overload & FILE_FIELD101) == FILE_FIELD) {
i++; /* can use packet->file, and didn't look at it yet */
break; overload |= FILE_FIELD101; /* "we looked at it" */
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)) {
optionptr = packet->file; optionptr = packet->file;
i = 0; rem = sizeof(packet->file);
length = sizeof(packet->file); continue;
curr = FILE_FIELD; }
} else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { 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; optionptr = packet->sname;
i = 0; rem = sizeof(packet->sname);
length = sizeof(packet->sname); continue;
curr = SNAME_FIELD; }
} else return NULL;
return NULL;
break;
default:
i += optionptr[OPT_LEN + i] + 2;
} }
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; return NULL;
} }
@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr)
int i = 0; int i = 0;
while (optionptr[i] != DHCP_END) { while (optionptr[i] != DHCP_END) {
if (optionptr[i] == DHCP_PADDING) if (optionptr[i] != DHCP_PADDING)
i++; i += optionptr[i + OPT_LEN] + 1;
else i++;
i += optionptr[i + OPT_LEN] + 2;
} }
return i; return i;
} }
/* add an option string to the options (an option string contains an option code, /* add an option string to the options */
* length, then data) */ /* option bytes: [code][len][data1][data2]..[dataLEN] */
int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
{ {
int end = end_option(optionptr); int end = end_option(optionptr);

View File

@ -7,7 +7,7 @@
# pragma GCC visibility push(hidden) # pragma GCC visibility push(hidden)
#endif #endif
#define TYPE_MASK 0x0F #define TYPE_MASK 0x0F
enum { enum {
OPTION_IP = 1, OPTION_IP = 1,
@ -24,8 +24,8 @@ enum {
OPTION_S32 OPTION_S32
}; };
#define OPTION_REQ 0x10 /* have the client request this option */ #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_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!! */ /* Do not modify below here unless you know what you are doing!! */
@ -34,67 +34,64 @@ enum {
/* DHCP protocol -- see RFC 2131 */ /* DHCP protocol -- see RFC 2131 */
#define DHCP_MAGIC 0x63825363 #define DHCP_MAGIC 0x63825363
/* DHCP option codes (partial list) */ /* DHCP option codes (partial list) */
#define DHCP_PADDING 0x00 #define DHCP_PADDING 0x00
#define DHCP_SUBNET 0x01 #define DHCP_SUBNET 0x01
#define DHCP_TIME_OFFSET 0x02 #define DHCP_TIME_OFFSET 0x02
#define DHCP_ROUTER 0x03 #define DHCP_ROUTER 0x03
#define DHCP_TIME_SERVER 0x04 #define DHCP_TIME_SERVER 0x04
#define DHCP_NAME_SERVER 0x05 #define DHCP_NAME_SERVER 0x05
#define DHCP_DNS_SERVER 0x06 #define DHCP_DNS_SERVER 0x06
#define DHCP_LOG_SERVER 0x07 #define DHCP_LOG_SERVER 0x07
#define DHCP_COOKIE_SERVER 0x08 #define DHCP_COOKIE_SERVER 0x08
#define DHCP_LPR_SERVER 0x09 #define DHCP_LPR_SERVER 0x09
#define DHCP_HOST_NAME 0x0c #define DHCP_HOST_NAME 0x0c
#define DHCP_BOOT_SIZE 0x0d #define DHCP_BOOT_SIZE 0x0d
#define DHCP_DOMAIN_NAME 0x0f #define DHCP_DOMAIN_NAME 0x0f
#define DHCP_SWAP_SERVER 0x10 #define DHCP_SWAP_SERVER 0x10
#define DHCP_ROOT_PATH 0x11 #define DHCP_ROOT_PATH 0x11
#define DHCP_IP_TTL 0x17 #define DHCP_IP_TTL 0x17
#define DHCP_MTU 0x1a #define DHCP_MTU 0x1a
#define DHCP_BROADCAST 0x1c #define DHCP_BROADCAST 0x1c
#define DHCP_NTP_SERVER 0x2a #define DHCP_NTP_SERVER 0x2a
#define DHCP_WINS_SERVER 0x2c #define DHCP_WINS_SERVER 0x2c
#define DHCP_REQUESTED_IP 0x32 #define DHCP_REQUESTED_IP 0x32
#define DHCP_LEASE_TIME 0x33 #define DHCP_LEASE_TIME 0x33
#define DHCP_OPTION_OVER 0x34 #define DHCP_OPTION_OVERLOAD 0x34
#define DHCP_MESSAGE_TYPE 0x35 #define DHCP_MESSAGE_TYPE 0x35
#define DHCP_SERVER_ID 0x36 #define DHCP_SERVER_ID 0x36
#define DHCP_PARAM_REQ 0x37 #define DHCP_PARAM_REQ 0x37
#define DHCP_MESSAGE 0x38 #define DHCP_MESSAGE 0x38
#define DHCP_MAX_SIZE 0x39 #define DHCP_MAX_SIZE 0x39
#define DHCP_T1 0x3a #define DHCP_T1 0x3a
#define DHCP_T2 0x3b #define DHCP_T2 0x3b
#define DHCP_VENDOR 0x3c #define DHCP_VENDOR 0x3c
#define DHCP_CLIENT_ID 0x3d #define DHCP_CLIENT_ID 0x3d
#define DHCP_FQDN 0x51 #define DHCP_FQDN 0x51
#define DHCP_END 0xFF #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 ETH_10MB 1
#define BOOTREPLY 2 #define ETH_10MB_LEN 6
#define ETH_10MB 1 #define DHCPDISCOVER 1 /* client -> server */
#define ETH_10MB_LEN 6 #define DHCPOFFER 2 /* client <- server */
#define DHCPREQUEST 3 /* client -> server */
#define DHCPDISCOVER 1 /* client -> server */ #define DHCPDECLINE 4 /* client -> server */
#define DHCPOFFER 2 /* client <- server */ #define DHCPACK 5 /* client <- server */
#define DHCPREQUEST 3 /* client -> server */ #define DHCPNAK 6 /* client <- server */
#define DHCPDECLINE 4 /* client -> server */ #define DHCPRELEASE 7 /* client -> server */
#define DHCPACK 5 /* client <- server */ #define DHCPINFORM 8 /* 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
struct dhcp_option { struct dhcp_option {
uint8_t flags; uint8_t flags;

View File

@ -135,7 +135,7 @@ static char **fill_envp(struct dhcpMessage *packet)
char **envp, **curr; char **envp, **curr;
const char *opt_name; const char *opt_name;
uint8_t *temp; uint8_t *temp;
char over = 0; uint8_t over = 0;
if (packet) { if (packet) {
for (i = 0; dhcp_options[i].code; i++) { for (i = 0; dhcp_options[i].code; i++) {
@ -147,7 +147,7 @@ static char **fill_envp(struct dhcpMessage *packet)
} }
if (packet->siaddr) if (packet->siaddr)
num_options++; num_options++;
temp = get_option(packet, DHCP_OPTION_OVER); temp = get_option(packet, DHCP_OPTION_OVERLOAD);
if (temp) if (temp)
over = *temp; over = *temp;
if (!(over & FILE_FIELD) && packet->file[0]) if (!(over & FILE_FIELD) && packet->file[0])

View File

@ -105,7 +105,7 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
uint32_t req_align; uint32_t req_align;
uint32_t lease_time_aligned = server_config.lease; uint32_t lease_time_aligned = server_config.lease;
uint32_t static_lease_ip; uint32_t static_lease_ip;
uint8_t *req, *lease_time; uint8_t *req, *lease_time, *p_host_name;
struct option_set *curr; struct option_set *curr;
struct in_addr addr; 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"); bb_error_msg("no IP addresses to give - OFFER abandoned");
return -1; 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"); bb_error_msg("lease pool is full - OFFER abandoned");
return -1; return -1;
} }
@ -201,6 +202,7 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
uint8_t *lease_time; uint8_t *lease_time;
uint32_t lease_time_aligned = server_config.lease; uint32_t lease_time_aligned = server_config.lease;
struct in_addr addr; struct in_addr addr;
uint8_t *p_host_name;
init_packet(&packet, oldpacket, DHCPACK); init_packet(&packet, oldpacket, DHCPACK);
packet.yiaddr = yiaddr; packet.yiaddr = yiaddr;
@ -232,7 +234,8 @@ int FAST_FUNC send_ACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
if (send_packet(&packet, 0) < 0) if (send_packet(&packet, 0) < 0)
return -1; 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) { if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
/* rewrite the file with leases at every new acceptance */ /* rewrite the file with leases at every new acceptance */
write_leases(); write_leases();