2 |
/* |
/* |
3 |
* leases.c -- tools to manage DHCP leases |
* leases.c -- tools to manage DHCP leases |
4 |
* Russ Dill <Russ.Dill@asu.edu> July 2001 |
* Russ Dill <Russ.Dill@asu.edu> July 2001 |
5 |
|
* |
6 |
|
* Licensed under GPLv2, see file LICENSE in this tarball for details. |
7 |
*/ |
*/ |
8 |
|
|
9 |
#include "common.h" |
#include "common.h" |
11 |
|
|
12 |
|
|
13 |
/* Find the oldest expired lease, NULL if there are no expired leases */ |
/* Find the oldest expired lease, NULL if there are no expired leases */ |
14 |
static struct dhcpOfferedAddr *oldest_expired_lease(void) |
static struct dyn_lease *oldest_expired_lease(void) |
15 |
{ |
{ |
16 |
struct dhcpOfferedAddr *oldest = NULL; |
struct dyn_lease *oldest_lease = NULL; |
17 |
// TODO: use monotonic_sec() |
leasetime_t oldest_time = time(NULL); |
|
unsigned long oldest_lease = time(0); |
|
18 |
unsigned i; |
unsigned i; |
19 |
|
|
20 |
for (i = 0; i < server_config.max_leases; i++) |
/* Unexpired leases have g_leases[i].expires >= current time |
21 |
if (oldest_lease > leases[i].expires) { |
* and therefore can't ever match */ |
22 |
oldest_lease = leases[i].expires; |
for (i = 0; i < server_config.max_leases; i++) { |
23 |
oldest = &(leases[i]); |
if (g_leases[i].expires < oldest_time) { |
24 |
|
oldest_time = g_leases[i].expires; |
25 |
|
oldest_lease = &g_leases[i]; |
26 |
} |
} |
27 |
return oldest; |
} |
28 |
|
return oldest_lease; |
29 |
} |
} |
30 |
|
|
31 |
|
|
32 |
/* clear every lease out that chaddr OR yiaddr matches and is nonzero */ |
/* Clear every lease out that chaddr OR yiaddr matches and is nonzero */ |
33 |
static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) |
static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr) |
34 |
{ |
{ |
35 |
unsigned i, j; |
unsigned i, j; |
37 |
for (j = 0; j < 16 && !chaddr[j]; j++) |
for (j = 0; j < 16 && !chaddr[j]; j++) |
38 |
continue; |
continue; |
39 |
|
|
40 |
for (i = 0; i < server_config.max_leases; i++) |
for (i = 0; i < server_config.max_leases; i++) { |
41 |
if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0) |
if ((j != 16 && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0) |
42 |
|| (yiaddr && leases[i].yiaddr == yiaddr) |
|| (yiaddr && g_leases[i].lease_nip == yiaddr) |
43 |
) { |
) { |
44 |
memset(&(leases[i]), 0, sizeof(leases[i])); |
memset(&g_leases[i], 0, sizeof(g_leases[i])); |
45 |
} |
} |
46 |
|
} |
47 |
} |
} |
48 |
|
|
49 |
|
|
50 |
/* add a lease into the table, clearing out any old ones */ |
/* Add a lease into the table, clearing out any old ones */ |
51 |
struct dhcpOfferedAddr* FAST_FUNC add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) |
struct dyn_lease* FAST_FUNC add_lease( |
52 |
|
const uint8_t *chaddr, uint32_t yiaddr, |
53 |
|
leasetime_t leasetime, |
54 |
|
const char *hostname, int hostname_len) |
55 |
{ |
{ |
56 |
struct dhcpOfferedAddr *oldest; |
struct dyn_lease *oldest; |
57 |
|
|
58 |
/* clean out any old ones */ |
/* clean out any old ones */ |
59 |
clear_lease(chaddr, yiaddr); |
clear_lease(chaddr, yiaddr); |
61 |
oldest = oldest_expired_lease(); |
oldest = oldest_expired_lease(); |
62 |
|
|
63 |
if (oldest) { |
if (oldest) { |
64 |
memcpy(oldest->chaddr, chaddr, 16); |
oldest->hostname[0] = '\0'; |
65 |
oldest->yiaddr = yiaddr; |
if (hostname) { |
66 |
oldest->expires = time(0) + lease; |
char *p; |
67 |
|
|
68 |
|
hostname_len++; /* include NUL */ |
69 |
|
if (hostname_len > sizeof(oldest->hostname)) |
70 |
|
hostname_len = sizeof(oldest->hostname); |
71 |
|
p = safe_strncpy(oldest->hostname, hostname, hostname_len); |
72 |
|
/* sanitization (s/non-ASCII/^/g) */ |
73 |
|
while (*p) { |
74 |
|
if (*p < ' ' || *p > 126) |
75 |
|
*p = '^'; |
76 |
|
p++; |
77 |
|
} |
78 |
|
} |
79 |
|
memcpy(oldest->lease_mac, chaddr, 6); |
80 |
|
oldest->lease_nip = yiaddr; |
81 |
|
oldest->expires = time(NULL) + leasetime; |
82 |
} |
} |
83 |
|
|
84 |
return oldest; |
return oldest; |
85 |
} |
} |
86 |
|
|
87 |
|
|
88 |
/* true if a lease has expired */ |
/* True if a lease has expired */ |
89 |
int FAST_FUNC lease_expired(struct dhcpOfferedAddr *lease) |
int FAST_FUNC is_expired_lease(struct dyn_lease *lease) |
90 |
{ |
{ |
91 |
return (lease->expires < (unsigned long) time(0)); |
return (lease->expires < (leasetime_t) time(NULL)); |
92 |
} |
} |
93 |
|
|
94 |
|
|
95 |
/* Find the first lease that matches chaddr, NULL if no match */ |
/* Find the first lease that matches MAC, NULL if no match */ |
96 |
struct dhcpOfferedAddr* FAST_FUNC find_lease_by_chaddr(const uint8_t *chaddr) |
struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac) |
97 |
{ |
{ |
98 |
unsigned i; |
unsigned i; |
99 |
|
|
100 |
for (i = 0; i < server_config.max_leases; i++) |
for (i = 0; i < server_config.max_leases; i++) |
101 |
if (!memcmp(leases[i].chaddr, chaddr, 16)) |
if (memcmp(g_leases[i].lease_mac, mac, 6) == 0) |
102 |
return &(leases[i]); |
return &g_leases[i]; |
103 |
|
|
104 |
return NULL; |
return NULL; |
105 |
} |
} |
106 |
|
|
107 |
|
|
108 |
/* Find the first lease that matches yiaddr, NULL is no match */ |
/* Find the first lease that matches IP, NULL is no match */ |
109 |
struct dhcpOfferedAddr* FAST_FUNC find_lease_by_yiaddr(uint32_t yiaddr) |
struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip) |
110 |
{ |
{ |
111 |
unsigned i; |
unsigned i; |
112 |
|
|
113 |
for (i = 0; i < server_config.max_leases; i++) |
for (i = 0; i < server_config.max_leases; i++) |
114 |
if (leases[i].yiaddr == yiaddr) |
if (g_leases[i].lease_nip == nip) |
115 |
return &(leases[i]); |
return &g_leases[i]; |
116 |
|
|
117 |
return NULL; |
return NULL; |
118 |
} |
} |
119 |
|
|
120 |
|
|
121 |
/* check is an IP is taken, if it is, add it to the lease table */ |
/* Check if the IP is taken; if it is, add it to the lease table */ |
122 |
static int nobody_responds_to_arp(uint32_t addr) |
static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac) |
123 |
{ |
{ |
124 |
/* 16 zero bytes */ |
/* 16 zero bytes */ |
125 |
static const uint8_t blank_chaddr[16] = { 0 }; |
static const uint8_t blank_chaddr[16] = { 0 }; |
128 |
struct in_addr temp; |
struct in_addr temp; |
129 |
int r; |
int r; |
130 |
|
|
131 |
r = arpping(addr, server_config.server, server_config.arp, server_config.interface); |
r = arpping(nip, safe_mac, |
132 |
|
server_config.server_nip, |
133 |
|
server_config.server_mac, |
134 |
|
server_config.interface); |
135 |
if (r) |
if (r) |
136 |
return r; |
return r; |
137 |
|
|
138 |
temp.s_addr = addr; |
temp.s_addr = nip; |
139 |
bb_info_msg("%s belongs to someone, reserving it for %u seconds", |
bb_info_msg("%s belongs to someone, reserving it for %u seconds", |
140 |
inet_ntoa(temp), (unsigned)server_config.conflict_time); |
inet_ntoa(temp), (unsigned)server_config.conflict_time); |
141 |
add_lease(blank_chaddr, addr, server_config.conflict_time); |
add_lease(blank_chaddr, nip, server_config.conflict_time, NULL, 0); |
142 |
return 0; |
return 0; |
143 |
} |
} |
144 |
|
|
145 |
|
|
146 |
/* find an assignable address, if check_expired is true, we check all the expired leases as well. |
/* Find a new usable (we think) address */ |
147 |
* Maybe this should try expired leases by age... */ |
uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) |
|
uint32_t FAST_FUNC find_address(int check_expired) |
|
148 |
{ |
{ |
149 |
uint32_t addr, ret; |
uint32_t addr; |
150 |
struct dhcpOfferedAddr *lease = NULL; |
struct dyn_lease *oldest_lease = NULL; |
151 |
|
|
152 |
addr = server_config.start_ip; /* addr is in host order here */ |
addr = server_config.start_ip; /* addr is in host order here */ |
153 |
for (; addr <= server_config.end_ip; addr++) { |
for (; addr <= server_config.end_ip; addr++) { |
154 |
|
uint32_t nip; |
155 |
|
struct dyn_lease *lease; |
156 |
|
|
157 |
/* ie, 192.168.55.0 */ |
/* ie, 192.168.55.0 */ |
158 |
if (!(addr & 0xFF)) |
if ((addr & 0xff) == 0) |
159 |
continue; |
continue; |
160 |
/* ie, 192.168.55.255 */ |
/* ie, 192.168.55.255 */ |
161 |
if ((addr & 0xFF) == 0xFF) |
if ((addr & 0xff) == 0xff) |
162 |
continue; |
continue; |
163 |
/* Only do if it isn't assigned as a static lease */ |
nip = htonl(addr); |
164 |
ret = htonl(addr); |
/* is this a static lease addr? */ |
165 |
if (!reservedIp(server_config.static_leases, ret)) { |
if (is_nip_reserved(server_config.static_leases, nip)) |
166 |
/* lease is not taken */ |
continue; |
167 |
lease = find_lease_by_yiaddr(ret); |
|
168 |
/* no lease or it expired and we are checking for expired leases */ |
lease = find_lease_by_nip(nip); |
169 |
if ((!lease || (check_expired && lease_expired(lease))) |
if (!lease) { |
170 |
&& nobody_responds_to_arp(ret) /* it isn't used on the network */ |
if (nobody_responds_to_arp(nip, safe_mac)) |
171 |
) { |
return nip; |
172 |
return ret; |
} else { |
173 |
} |
if (!oldest_lease || lease->expires < oldest_lease->expires) |
174 |
|
oldest_lease = lease; |
175 |
} |
} |
176 |
} |
} |
177 |
|
|
178 |
|
if (oldest_lease && is_expired_lease(oldest_lease) |
179 |
|
&& nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac) |
180 |
|
) { |
181 |
|
return oldest_lease->lease_nip; |
182 |
|
} |
183 |
|
|
184 |
return 0; |
return 0; |
185 |
} |
} |