int udhcpd_main(int argc UNUSED_PARAM, char **argv)
{
fd_set rfds;
- struct timeval tv;
- int server_socket = -1, bytes, retval, max_sock;
+ int server_socket = -1, retval, max_sock;
struct dhcpMessage packet;
uint8_t *state, *server_id, *requested;
uint32_t server_id_aligned = server_id_aligned; /* for compiler */
timeout_end = monotonic_sec() + server_config.auto_time;
while (1) { /* loop until universe collapses */
+ int bytes;
+ struct timeval tv;
if (server_socket < 0) {
server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
case SIGTERM:
bb_info_msg("Received a SIGTERM");
goto ret0;
- case 0: break; /* no signal */
- default: continue; /* signal or error (probably EINTR) */
+ case 0: /* no signal: read a packet */
+ break;
+ default: /* signal or error (probably EINTR): back to select */
+ continue;
}
- bytes = udhcp_recv_kernel_packet(&packet, server_socket); /* this waits for a packet - idle */
+ bytes = udhcp_recv_kernel_packet(&packet, server_socket);
if (bytes < 0) {
+ /* bytes can also be -2 ("bad packet data") */
if (bytes == -1 && errno != EINTR) {
DEBUG("error on read, %s, reopening socket", strerror(errno));
close(server_socket);
/* Look for a static lease */
static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
-
if (static_lease_ip) {
bb_info_msg("Found static lease: %x", static_lease_ip);
struct static_lease {
struct static_lease *next;
- uint8_t *mac;
- uint32_t *ip;
+ uint32_t ip;
+ uint8_t mac[6];
};
struct server_config_t {
char *interface; /* The name of the interface to use */
int ifindex; /* Index number of the interface to use */
uint8_t arp[6]; /* Our arp address */
- char remaining; /* should the lease file be interpreted as lease time remaining, or
- * as the time the lease expires */
+// disabled: dumpleases has no way of knowing this value,
+// and will break if it's off. Now it's on always.
+// char remaining; /* Should the lease time in lease file
+// * be written as lease time remaining, or
+// * as the absolute time the lease expires */
uint32_t lease; /* lease time in seconds (host order) */
uint32_t max_leases; /* maximum number of leases (including reserved address) */
uint32_t auto_time; /* how long should udhcpd wait before writing a config file.
* decline message */
uint32_t conflict_time; /* how long an arp conflict offender is leased for */
uint32_t offer_time; /* how long an offered address is reserved */
- uint32_t min_lease; /* minimum lease a client can request */
+ uint32_t min_lease; /* minimum lease time a client can request */
+ uint32_t siaddr; /* next server bootp option */
char *lease_file;
char *pidfile;
char *notify_file; /* What to run whenever leases are written */
- uint32_t siaddr; /* next server bootp option */
char *sname; /* bootp server name */
char *boot_file; /* bootp boot file option */
struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
/*** leases.h ***/
+typedef uint32_t leasetime_t;
+typedef int32_t signed_leasetime_t;
+
struct dhcpOfferedAddr {
uint8_t chaddr[16];
- uint32_t yiaddr; /* network order */
- uint32_t expires; /* host order */
+ /* In network order */
+ uint32_t yiaddr;
+ /* Unix time when lease expires, regardless of value of
+ * server_config.remaining. Kept in memory in host order.
+ * When written to file, converted to network order
+ * and optionally adjusted (current time subtracted)
+ * if server_config.remaining = 1 */
+ leasetime_t expires;
};
-struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) FAST_FUNC;
+struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, leasetime_t leasetime) 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;
-uint32_t find_address(int check_expired) FAST_FUNC;
+uint32_t find_free_or_expired_address(void) FAST_FUNC;
/*** static_leases.h ***/
/* Config file will pass static lease info to this function which will add it
* to a data structure that can be searched later */
-int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip) FAST_FUNC;
+void addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip) FAST_FUNC;
/* Check to see if a mac has an associated static lease */
uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) FAST_FUNC;
/* Check to see if an ip is reserved as a static ip */
-uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip) FAST_FUNC;
+int reservedIp(struct static_lease *lease_struct, uint32_t ip) FAST_FUNC;
/* Print out static leases just to check what's going on (debug code) */
void printStaticLeases(struct static_lease **lease_struct) FAST_FUNC;
int fd;
int i;
unsigned opt;
- time_t expires;
+ leasetime_t expires;
+ leasetime_t curr;
const char *file = LEASES_FILE;
struct dhcpOfferedAddr lease;
struct in_addr addr;
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" */
+
+ curr = time(NULL);
while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
- printf(":%02x"+1, lease.chaddr[0]);
- for (i = 1; i < 6; i++) {
- printf(":%02x", lease.chaddr[i]);
+ const char *fmt = ":%02x" + 1;
+ for (i = 0; i < 6; i++) {
+ printf(fmt, lease.chaddr[i]);
+ fmt = ":%02x";
}
addr.s_addr = lease.yiaddr;
printf(" %-15s ", inet_ntoa(addr));
+ if (lease.expires == 0) {
+ puts("expired");
+ continue;
+ }
expires = ntohl(lease.expires);
if (!(opt & OPT_a)) { /* no -a */
- if (!expires)
- puts("expired");
- else {
- unsigned d, h, m;
- d = expires / (24*60*60); expires %= (24*60*60);
- h = expires / (60*60); expires %= (60*60);
- m = expires / 60; expires %= 60;
- if (d) printf("%u days ", d);
- printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
- }
- } else /* -a */
- fputs(ctime(&expires), stdout);
+ unsigned d, h, m;
+ d = expires / (24*60*60); expires %= (24*60*60);
+ h = expires / (60*60); expires %= (60*60);
+ m = expires / 60; expires %= 60;
+ if (d)
+ printf("%u days ", d);
+ printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
+ } else { /* -a */
+ time_t t = expires + curr;
+ fputs(ctime(&t), stdout);
+ }
}
/* close(fd); */
static int read_mac(const char *line, void *arg)
{
- struct ether_addr *temp_ether_addr;
-
- temp_ether_addr = ether_aton_r(line, (struct ether_addr *)arg);
- if (temp_ether_addr == NULL)
- return 0;
- return 1;
+ return NULL == ether_aton_r(line, (struct ether_addr *)arg);
}
char *line;
char *mac_string;
char *ip_string;
- uint8_t *mac_bytes;
- uint32_t *ip;
-
- /* Allocate memory for addresses */
- mac_bytes = xmalloc(sizeof(unsigned char) * 8);
- ip = xmalloc(sizeof(uint32_t));
+ struct ether_addr mac_bytes;
+ uint32_t ip;
/* Read mac */
line = (char *) const_line;
- mac_string = strtok(line, " \t");
- read_mac(mac_string, mac_bytes);
+ mac_string = strtok_r(line, " \t", &line);
+ read_mac(mac_string, &mac_bytes);
/* Read ip */
- ip_string = strtok(NULL, " \t");
- read_ip(ip_string, ip);
+ ip_string = strtok_r(NULL, " \t", &line);
+ read_ip(ip_string, &ip);
- addStaticLease(arg, mac_bytes, ip);
+ addStaticLease(arg, (uint8_t*) &mac_bytes, ip);
if (ENABLE_UDHCP_DEBUG) printStaticLeases(arg);
/* Avoid "max_leases value not sane" warning by setting default
* to default_end_ip - default_start_ip + 1: */
{"max_leases", read_u32, &(server_config.max_leases), "235"},
- {"remaining", read_yn, &(server_config.remaining), "yes"},
+// {"remaining", read_yn, &(server_config.remaining), "yes"},
{"auto_time", read_u32, &(server_config.auto_time), "7200"},
{"decline_time", read_u32, &(server_config.decline_time), "3600"},
{"conflict_time",read_u32, &(server_config.conflict_time),"3600"},
{"sname", read_str, &(server_config.sname), ""},
{"boot_file", read_str, &(server_config.boot_file), ""},
{"static_lease", read_staticlease, &(server_config.static_leases), ""},
- /* ADDME: static lease */
};
enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
void FAST_FUNC write_leases(void)
{
- int fp;
+ int fd;
unsigned i;
- time_t curr = time(0);
- unsigned long tmp_time;
+ leasetime_t curr;
- fp = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
- if (fp < 0) {
+ fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
+ if (fd < 0)
return;
- }
+
+ curr = time(NULL);
+//TODO: write out current time? Readers need to adjust .expires field
+// to account for time between file was written and when it was read back.
for (i = 0; i < server_config.max_leases; i++) {
- if (leases[i].yiaddr != 0) {
-
- /* screw with the time in the struct, for easier writing */
- tmp_time = leases[i].expires;
-
- if (server_config.remaining) {
- if (lease_expired(&(leases[i])))
- leases[i].expires = 0;
- else leases[i].expires -= curr;
- } /* else stick with the time we got */
- leases[i].expires = htonl(leases[i].expires);
- // FIXME: error check??
- full_write(fp, &leases[i], sizeof(leases[i]));
-
- /* then restore it when done */
- leases[i].expires = tmp_time;
- }
+ leasetime_t tmp_time;
+
+ if (leases[i].yiaddr == 0)
+ continue;
+
+ /* screw with the time in the struct, for easier writing */
+ tmp_time = leases[i].expires;
+
+ //if (server_config.remaining) {
+ leases[i].expires -= curr;
+ if ((signed_leasetime_t) leases[i].expires < 0)
+ leases[i].expires = 0;
+ //} /* else stick with the time we got */
+ leases[i].expires = htonl(leases[i].expires);
+
+ /* No error check. If the file gets truncated,
+ * we lose some leases on restart. Oh well. */
+ full_write(fd, &leases[i], sizeof(leases[i]));
+
+ /* then restore it when done */
+ leases[i].expires = tmp_time;
}
- close(fp);
+ close(fd);
if (server_config.notify_file) {
// TODO: vfork-based child creation
void FAST_FUNC read_leases(const char *file)
{
- int fp;
+ int fd;
unsigned i;
+// leasetime_t curr;
struct dhcpOfferedAddr lease;
- fp = open_or_warn(file, O_RDONLY);
- if (fp < 0) {
+ fd = open_or_warn(file, O_RDONLY);
+ if (fd < 0)
return;
- }
+// curr = time(NULL);
i = 0;
while (i < server_config.max_leases
- && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)
+ && full_read(fd, &lease, sizeof(lease)) == sizeof(lease)
) {
- /* ADDME: is it a static lease */
+ /* ADDME: what if it matches some static lease? */
uint32_t y = ntohl(lease.yiaddr);
if (y >= server_config.start_ip && y <= server_config.end_ip) {
- lease.expires = ntohl(lease.expires);
- if (!server_config.remaining)
- lease.expires -= time(NULL);
- if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
+ leasetime_t expires = ntohl(lease.expires);
+// if (!server_config.remaining)
+// expires -= curr;
+ /* NB: add_lease takes "relative time", IOW,
+ * lease duration, not lease deadline. */
+ if (!(add_lease(lease.chaddr, lease.yiaddr, expires))) {
bb_error_msg("too many leases while loading %s", file);
break;
}
}
}
DEBUG("Read %d leases", i);
- close(fp);
+ close(fd);
}
/* Find the oldest expired lease, NULL if there are no expired leases */
static struct dhcpOfferedAddr *oldest_expired_lease(void)
{
- struct dhcpOfferedAddr *oldest = NULL;
-// TODO: use monotonic_sec()
- unsigned long oldest_lease = time(0);
+ struct dhcpOfferedAddr *oldest_lease = NULL;
+ leasetime_t oldest_time = time(NULL);
unsigned i;
- for (i = 0; i < server_config.max_leases; i++)
- if (oldest_lease > leases[i].expires) {
- oldest_lease = leases[i].expires;
- oldest = &(leases[i]);
+ /* Unexpired leases have leases[i].expires >= current time
+ * and therefore can't ever match */
+ for (i = 0; i < server_config.max_leases; i++) {
+ if (leases[i].expires < oldest_time) {
+ oldest_time = leases[i].expires;
+ oldest_lease = &(leases[i]);
}
- return oldest;
+ }
+ return oldest_lease;
}
-/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
+/* Clear every lease out that chaddr OR yiaddr matches and is nonzero */
static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
{
unsigned i, j;
for (j = 0; j < 16 && !chaddr[j]; j++)
continue;
- for (i = 0; i < server_config.max_leases; i++)
+ for (i = 0; i < server_config.max_leases; i++) {
if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
|| (yiaddr && leases[i].yiaddr == yiaddr)
) {
memset(&(leases[i]), 0, sizeof(leases[i]));
}
+ }
}
-/* add a lease into the table, clearing out any old ones */
-struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
+/* 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 *oldest;
if (oldest) {
memcpy(oldest->chaddr, chaddr, 16);
oldest->yiaddr = yiaddr;
- oldest->expires = time(0) + lease;
+ oldest->expires = time(NULL) + leasetime;
}
return oldest;
}
-/* true if a lease has expired */
+/* True if a lease has expired */
int FAST_FUNC lease_expired(struct dhcpOfferedAddr *lease)
{
- return (lease->expires < (unsigned long) time(0));
+ return (lease->expires < (leasetime_t) time(NULL));
}
}
-/* find an assignable address, if check_expired is true, we check all the expired leases as well.
- * Maybe this should try expired leases by age... */
-uint32_t FAST_FUNC find_address(int check_expired)
+/* Find a new usable (we think) address. */
+uint32_t FAST_FUNC find_free_or_expired_address(void)
{
- uint32_t addr, ret;
- struct dhcpOfferedAddr *lease = NULL;
+ uint32_t addr;
+ struct dhcpOfferedAddr *oldest_lease = NULL;
addr = server_config.start_ip; /* addr is in host order here */
for (; addr <= server_config.end_ip; addr++) {
+ uint32_t net_addr;
+ struct dhcpOfferedAddr *lease;
+
/* ie, 192.168.55.0 */
- if (!(addr & 0xFF))
+ if ((addr & 0xff) == 0)
continue;
/* ie, 192.168.55.255 */
- if ((addr & 0xFF) == 0xFF)
+ if ((addr & 0xff) == 0xff)
continue;
- /* Only do if it isn't assigned as a static lease */
- ret = htonl(addr);
- if (!reservedIp(server_config.static_leases, ret)) {
- /* lease is not taken */
- lease = find_lease_by_yiaddr(ret);
- /* no lease or it expired and we are checking for expired leases */
- if ((!lease || (check_expired && lease_expired(lease)))
- && nobody_responds_to_arp(ret) /* it isn't used on the network */
- ) {
- return ret;
- }
+ net_addr = htonl(addr);
+ /* addr has a static lease? */
+ if (reservedIp(server_config.static_leases, net_addr))
+ continue;
+
+ lease = find_lease_by_yiaddr(net_addr);
+ if (!lease) {
+ if (nobody_responds_to_arp(net_addr))
+ return net_addr;
+ } else {
+ if (!oldest_lease || lease->expires < oldest_lease->expires)
+ oldest_lease = lease;
}
}
+
+ if (oldest_lease && lease_expired(oldest_lease)
+ && nobody_responds_to_arp(oldest_lease->yiaddr)
+ ) {
+ return oldest_lease->yiaddr;
+ }
+
return 0;
}
int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
{
struct dhcpMessage packet;
- struct dhcpOfferedAddr *lease = NULL;
uint32_t req_align;
uint32_t lease_time_aligned = server_config.lease;
+ uint32_t static_lease_ip;
uint8_t *req, *lease_time;
struct option_set *curr;
struct in_addr addr;
- uint32_t static_lease_ip;
-
init_packet(&packet, oldpacket, DHCPOFFER);
static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr);
/* ADDME: if static, short circuit */
if (!static_lease_ip) {
- /* the client is in our lease/offered table */
+ struct dhcpOfferedAddr *lease;
+
lease = find_lease_by_chaddr(oldpacket->chaddr);
+ /* the client is in our lease/offered table */
if (lease) {
- if (!lease_expired(lease))
- lease_time_aligned = lease->expires - time(0);
+ signed_leasetime_t tmp = lease->expires - time(NULL);
+ if (tmp >= 0)
+ lease_time_aligned = tmp;
packet.yiaddr = lease->yiaddr;
- /* Or the client has a requested ip */
- } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP))
+ /* Or the client has requested an ip */
+ } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
/* Don't look here (ugly hackish thing to do) */
- && memcpy(&req_align, req, 4)
+ && (move_from_unaligned32(req_align, req), 1)
/* and the ip is in the lease range */
&& ntohl(req_align) >= server_config.start_ip
&& ntohl(req_align) <= server_config.end_ip
- && !static_lease_ip /* Check that its not a static lease */
/* and is not already taken/offered */
&& (!(lease = find_lease_by_yiaddr(req_align))
- /* or its taken, but expired */ /* ADDME: or maybe in here */
+ /* or its taken, but expired */
|| lease_expired(lease))
) {
- packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
- /* otherwise, find a free IP */
+ packet.yiaddr = req_align;
+ /* otherwise, find a free IP */
} else {
- /* Is it a static lease? (No, because find_address skips static lease) */
- packet.yiaddr = find_address(0);
- /* try for an expired lease */
- if (!packet.yiaddr)
- packet.yiaddr = find_address(1);
+ packet.yiaddr = find_free_or_expired_address();
}
if (!packet.yiaddr) {
/* Make sure we aren't just using the lease time from the previous offer */
if (lease_time_aligned < server_config.min_lease)
- lease_time_aligned = server_config.lease;
- /* ADDME: end of short circuit */
+ lease_time_aligned = server_config.min_lease;
} else {
/* It is a static lease... use it */
packet.yiaddr = static_lease_ip;
if (lease_time_aligned > server_config.lease)
lease_time_aligned = server_config.lease;
else if (lease_time_aligned < server_config.min_lease)
- lease_time_aligned = server_config.lease;
+ lease_time_aligned = server_config.min_lease;
}
add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_aligned));
/* Takes the address of the pointer to the static_leases linked list,
* Address to a 6 byte mac address
* Address to a 4 byte ip address */
-int FAST_FUNC addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip)
+void FAST_FUNC addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t ip)
{
- struct static_lease *cur;
struct static_lease *new_static_lease;
/* Build new node */
- new_static_lease = xmalloc(sizeof(struct static_lease));
- new_static_lease->mac = mac;
+ new_static_lease = xzalloc(sizeof(struct static_lease));
+ memcpy(new_static_lease->mac, mac, 6);
new_static_lease->ip = ip;
- new_static_lease->next = NULL;
+ /*new_static_lease->next = NULL;*/
/* If it's the first node to be added... */
if (*lease_struct == NULL) {
*lease_struct = new_static_lease;
} else {
- cur = *lease_struct;
- while (cur->next) {
+ struct static_lease *cur = *lease_struct;
+ while (cur->next)
cur = cur->next;
- }
-
cur->next = new_static_lease;
}
-
- return 1;
}
/* Check to see if a mac has an associated static lease */
-uint32_t FAST_FUNC getIpByMac(struct static_lease *lease_struct, void *arg)
+uint32_t FAST_FUNC getIpByMac(struct static_lease *lease_struct, void *mac)
{
- uint32_t return_ip;
- struct static_lease *cur = lease_struct;
- uint8_t *mac = arg;
-
- return_ip = 0;
-
- while (cur) {
- /* If the client has the correct mac */
- if (memcmp(cur->mac, mac, 6) == 0) {
- return_ip = *(cur->ip);
- }
-
- cur = cur->next;
+ while (lease_struct) {
+ if (memcmp(lease_struct->mac, mac, 6) == 0)
+ return lease_struct->ip;
+ lease_struct = lease_struct->next;
}
- return return_ip;
+ return 0;
}
/* Check to see if an ip is reserved as a static ip */
-uint32_t FAST_FUNC reservedIp(struct static_lease *lease_struct, uint32_t ip)
+int FAST_FUNC reservedIp(struct static_lease *lease_struct, uint32_t ip)
{
- struct static_lease *cur = lease_struct;
-
- uint32_t return_val = 0;
-
- while (cur) {
- /* If the client has the correct ip */
- if (*cur->ip == ip)
- return_val = 1;
-
- cur = cur->next;
+ while (lease_struct) {
+ if (lease_struct->ip == ip)
+ return 1;
+ lease_struct = lease_struct->next;
}
- return return_val;
+ return 0;
}
#if ENABLE_UDHCP_DEBUG
/* Takes the address of the pointer to the static_leases linked list */
void FAST_FUNC printStaticLeases(struct static_lease **arg)
{
- /* Get a pointer to the linked list */
struct static_lease *cur = *arg;
while (cur) {
- /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */
- printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac));
- /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */
- printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip));
-
+ printf("PrintStaticLeases: Lease mac Value: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ cur->mac[0], cur->mac[1], cur->mac[2],
+ cur->mac[3], cur->mac[4], cur->mac[5]
+ );
+ printf("PrintStaticLeases: Lease ip Value: %x\n", cur->ip);
cur = cur->next;
}
}