#define SERVER_PORT 67
#endif
-extern struct dhcpOfferedAddr *leases;
-
/*** leases.h ***/
* 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;
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;
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");
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;
}
/* 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);
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;
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;
}
};
-/* 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;
}
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);
# pragma GCC visibility push(hidden)
#endif
-#define TYPE_MASK 0x0F
+#define TYPE_MASK 0x0F
enum {
OPTION_IP = 1,
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!! */
/* 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;
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++) {
}
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])
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;
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;
}
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;
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();