[1770] | 1 | /* vi: set sw=4 ts=4: */
|
---|
[821] | 2 | /*
|
---|
| 3 | * leases.c -- tools to manage DHCP leases
|
---|
| 4 | * Russ Dill <Russ.Dill@asu.edu> July 2001
|
---|
| 5 | */
|
---|
| 6 |
|
---|
[1770] | 7 | #include "common.h"
|
---|
[821] | 8 | #include "dhcpd.h"
|
---|
| 9 |
|
---|
| 10 |
|
---|
[1770] | 11 | /* Find the oldest expired lease, NULL if there are no expired leases */
|
---|
| 12 | static struct dhcpOfferedAddr *oldest_expired_lease(void)
|
---|
| 13 | {
|
---|
| 14 | struct dhcpOfferedAddr *oldest = NULL;
|
---|
| 15 | // TODO: use monotonic_sec()
|
---|
| 16 | unsigned long oldest_lease = time(0);
|
---|
| 17 | unsigned i;
|
---|
[821] | 18 |
|
---|
[1770] | 19 | for (i = 0; i < server_config.max_leases; i++)
|
---|
| 20 | if (oldest_lease > leases[i].expires) {
|
---|
| 21 | oldest_lease = leases[i].expires;
|
---|
| 22 | oldest = &(leases[i]);
|
---|
| 23 | }
|
---|
| 24 | return oldest;
|
---|
| 25 | }
|
---|
[821] | 26 |
|
---|
[1770] | 27 |
|
---|
[821] | 28 | /* clear every lease out that chaddr OR yiaddr matches and is nonzero */
|
---|
[1770] | 29 | static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
|
---|
[821] | 30 | {
|
---|
[1770] | 31 | unsigned i, j;
|
---|
[821] | 32 |
|
---|
[1770] | 33 | for (j = 0; j < 16 && !chaddr[j]; j++)
|
---|
| 34 | continue;
|
---|
[821] | 35 |
|
---|
| 36 | for (i = 0; i < server_config.max_leases; i++)
|
---|
[1770] | 37 | if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
|
---|
| 38 | || (yiaddr && leases[i].yiaddr == yiaddr)
|
---|
| 39 | ) {
|
---|
| 40 | memset(&(leases[i]), 0, sizeof(leases[i]));
|
---|
[821] | 41 | }
|
---|
| 42 | }
|
---|
| 43 |
|
---|
| 44 |
|
---|
| 45 | /* add a lease into the table, clearing out any old ones */
|
---|
[1770] | 46 | struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
|
---|
[821] | 47 | {
|
---|
| 48 | struct dhcpOfferedAddr *oldest;
|
---|
| 49 |
|
---|
| 50 | /* clean out any old ones */
|
---|
| 51 | clear_lease(chaddr, yiaddr);
|
---|
| 52 |
|
---|
| 53 | oldest = oldest_expired_lease();
|
---|
| 54 |
|
---|
| 55 | if (oldest) {
|
---|
| 56 | memcpy(oldest->chaddr, chaddr, 16);
|
---|
| 57 | oldest->yiaddr = yiaddr;
|
---|
| 58 | oldest->expires = time(0) + lease;
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | return oldest;
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 |
|
---|
| 65 | /* true if a lease has expired */
|
---|
| 66 | int lease_expired(struct dhcpOfferedAddr *lease)
|
---|
| 67 | {
|
---|
| 68 | return (lease->expires < (unsigned long) time(0));
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 |
|
---|
| 72 | /* Find the first lease that matches chaddr, NULL if no match */
|
---|
[1770] | 73 | struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr)
|
---|
[821] | 74 | {
|
---|
[1770] | 75 | unsigned i;
|
---|
[821] | 76 |
|
---|
| 77 | for (i = 0; i < server_config.max_leases; i++)
|
---|
[1770] | 78 | if (!memcmp(leases[i].chaddr, chaddr, 16))
|
---|
| 79 | return &(leases[i]);
|
---|
[821] | 80 |
|
---|
| 81 | return NULL;
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 |
|
---|
| 85 | /* Find the first lease that matches yiaddr, NULL is no match */
|
---|
| 86 | struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
|
---|
| 87 | {
|
---|
[1770] | 88 | unsigned i;
|
---|
[821] | 89 |
|
---|
| 90 | for (i = 0; i < server_config.max_leases; i++)
|
---|
[1770] | 91 | if (leases[i].yiaddr == yiaddr)
|
---|
| 92 | return &(leases[i]);
|
---|
[821] | 93 |
|
---|
| 94 | return NULL;
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 |
|
---|
| 98 | /* check is an IP is taken, if it is, add it to the lease table */
|
---|
[1770] | 99 | static int nobody_responds_to_arp(uint32_t addr)
|
---|
[821] | 100 | {
|
---|
[1770] | 101 | static const uint8_t blank_chaddr[16]; /* 16 zero bytes */
|
---|
| 102 |
|
---|
[821] | 103 | struct in_addr temp;
|
---|
[1770] | 104 | int r;
|
---|
[821] | 105 |
|
---|
[1770] | 106 | r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
|
---|
| 107 | if (r)
|
---|
| 108 | return r;
|
---|
| 109 |
|
---|
| 110 | temp.s_addr = addr;
|
---|
| 111 | bb_info_msg("%s belongs to someone, reserving it for %u seconds",
|
---|
| 112 | inet_ntoa(temp), (unsigned)server_config.conflict_time);
|
---|
| 113 | add_lease(blank_chaddr, addr, server_config.conflict_time);
|
---|
| 114 | return 0;
|
---|
[821] | 115 | }
|
---|
| 116 |
|
---|
| 117 |
|
---|
[1770] | 118 | /* find an assignable address, if check_expired is true, we check all the expired leases as well.
|
---|
[821] | 119 | * Maybe this should try expired leases by age... */
|
---|
| 120 | uint32_t find_address(int check_expired)
|
---|
| 121 | {
|
---|
| 122 | uint32_t addr, ret;
|
---|
| 123 | struct dhcpOfferedAddr *lease = NULL;
|
---|
| 124 |
|
---|
[1770] | 125 | addr = server_config.start_ip; /* addr is in host order here */
|
---|
| 126 | for (; addr <= server_config.end_ip; addr++) {
|
---|
[821] | 127 | /* ie, 192.168.55.0 */
|
---|
[1770] | 128 | if (!(addr & 0xFF))
|
---|
| 129 | continue;
|
---|
[821] | 130 | /* ie, 192.168.55.255 */
|
---|
[1770] | 131 | if ((addr & 0xFF) == 0xFF)
|
---|
| 132 | continue;
|
---|
| 133 | /* Only do if it isn't assigned as a static lease */
|
---|
[821] | 134 | ret = htonl(addr);
|
---|
[1770] | 135 | if (!reservedIp(server_config.static_leases, ret)) {
|
---|
| 136 | /* lease is not taken */
|
---|
| 137 | lease = find_lease_by_yiaddr(ret);
|
---|
| 138 | /* no lease or it expired and we are checking for expired leases */
|
---|
| 139 | if ((!lease || (check_expired && lease_expired(lease)))
|
---|
| 140 | && nobody_responds_to_arp(ret) /* it isn't used on the network */
|
---|
| 141 | ) {
|
---|
| 142 | return ret;
|
---|
| 143 | }
|
---|
[821] | 144 | }
|
---|
| 145 | }
|
---|
| 146 | return 0;
|
---|
| 147 | }
|
---|