1
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 dated June, 1991.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
13
/* Author's email: simon@thekelleys.org.uk */
17
static struct dhcp_lease *leases;
18
static FILE *lease_file;
20
enum { no, yes, force } file_dirty;
21
static int leases_left;
23
void lease_init(struct daemon *daemon, time_t now)
25
unsigned int a0, a1, a2, a3;
28
unsigned char hwaddr[ETHER_ADDR_LEN];
30
struct dhcp_lease *lease;
35
leases_left = daemon->dhcp_max;
37
/* NOTE: need a+ mode to create file if it doesn't exist */
38
if (!(lease_file = fopen(daemon->lease_file, "a+")))
39
die("cannot open or create leases file: %s", NULL);
41
/* a+ mode lease pointer at end. */
44
/* client-id max length is 255 which is 255*2 digits + 254 colons
45
borrow DNS packet buffer which is always larger than 1000 bytes */
46
while (fscanf(lease_file, "%lu %40s %d.%d.%d.%d %255s %764s",
47
&ei, daemon->dhcp_buff2, &a0, &a1, &a2, &a3,
48
daemon->dhcp_buff, daemon->packet) == 8)
50
#ifdef HAVE_BROKEN_RTC
52
expires = (time_t)ei + now;
56
/* strictly time_t is opaque, but this hack should work on all sane systems,
57
even when sizeof(time_t) == 8 */
60
if (ei != 0 && difftime(now, expires) > 0)
63
continue; /* expired */
67
parse_hex(daemon->dhcp_buff2, hwaddr, ETHER_ADDR_LEN, NULL);
68
addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3);
70
/* decode hex in place */
71
if (strcmp(daemon->packet, "*") == 0)
74
clid_len = parse_hex(daemon->packet, daemon->packet, 255, NULL);
76
if (!(lease = lease_allocate(hwaddr, daemon->packet, clid_len, addr)))
77
die ("too many stored leases", NULL);
79
lease->expires = expires;
81
if (strcmp(daemon->dhcp_buff, "*") != 0)
82
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix);
86
file_dirty = has_old ? yes: no;
88
daemon->lease_fd = fileno(lease_file);
91
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
93
/* changes to the config may change current leases. */
95
struct dhcp_lease *lease;
96
struct dhcp_config *config;
98
for (lease = leases; lease; lease = lease->next)
99
if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
100
(config->flags & CONFIG_NAME))
101
lease_set_hostname(lease, config->hostname, domain);
104
void lease_update_file(int always, time_t now)
106
struct dhcp_lease *lease;
107
int i = always; /* avoid warning */
108
unsigned long expires;
110
#ifdef HAVE_BROKEN_RTC
111
if (always || file_dirty == force)
113
lease_prune(NULL, now);
115
if (file_dirty != no)
119
ftruncate(fileno(lease_file), 0);
121
for (lease = leases; lease; lease = lease->next)
123
#ifdef HAVE_BROKEN_RTC
125
expires = (unsigned long) difftime(lease->expires, now);
129
expires = now; /* eliminate warning */
130
expires = (unsigned long)lease->expires;
132
fprintf(lease_file, "%lu %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s ",
133
expires, lease->hwaddr[0], lease->hwaddr[1],
134
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
135
lease->hwaddr[5], inet_ntoa(lease->addr),
136
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
138
if (lease->clid && lease->clid_len != 0)
140
for (i = 0; i < lease->clid_len - 1; i++)
141
fprintf(lease_file, "%.2x:", lease->clid[i]);
142
fprintf(lease_file, "%.2x\n", lease->clid[i]);
145
fprintf(lease_file, "*\n");
150
fsync(fileno(lease_file));
155
void lease_update_dns(struct daemon *daemon)
157
struct dhcp_lease *lease;
163
for (lease = leases; lease; lease = lease->next)
165
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
166
cache_add_dhcp_entry(daemon, lease->hostname, &lease->addr, lease->expires);
173
void lease_prune(struct dhcp_lease *target, time_t now)
175
struct dhcp_lease *lease, *tmp, **up;
177
for (lease = leases, up = &leases; lease; lease = tmp)
180
if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
184
*up = lease->next; /* unlink */
187
free(lease->hostname);
203
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr,
204
unsigned char *clid, int clid_len)
206
struct dhcp_lease *lease;
209
for (lease = leases; lease; lease = lease->next)
210
if (lease->clid && clid_len == lease->clid_len &&
211
memcmp(clid, lease->clid, clid_len) == 0)
214
for (lease = leases; lease; lease = lease->next)
215
if ((!lease->clid || !clid) &&
216
memcmp(hwaddr, lease->hwaddr, ETHER_ADDR_LEN) == 0)
222
struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
224
struct dhcp_lease *lease;
226
for (lease = leases; lease; lease = lease->next)
227
if (lease->addr.s_addr == addr.s_addr)
234
struct dhcp_lease *lease_allocate(unsigned char *hwaddr, unsigned char *clid,
235
int clid_len, struct in_addr addr)
237
struct dhcp_lease *lease;
238
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
242
lease->hostname = lease->fqdn = NULL;
244
memset(lease->hwaddr, 0, ETHER_ADDR_LEN);
247
if (!lease_set_hwaddr(lease, hwaddr, clid, clid_len))
253
lease->next = leases;
262
void lease_set_expires(struct dhcp_lease *lease, time_t exp)
264
if (exp != lease->expires)
269
lease->expires = exp;
272
int lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
273
unsigned char *clid, int clid_len)
275
if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0)
278
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
281
/* only update clid when one is available, stops packets
282
without a clid removing the record. Lease init uses
283
clid_len == 0 for no clid. */
284
if (clid_len != 0 && clid)
289
if (lease->clid_len != clid_len)
294
if (!(lease->clid = malloc(clid_len)))
297
else if (memcmp(lease->clid, clid, clid_len) != 0)
300
lease->clid_len = clid_len;
301
memcpy(lease->clid, clid, clid_len);
307
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
309
struct dhcp_lease *lease_tmp;
310
char *new_name = NULL, *new_fqdn = NULL;
312
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
315
if (!name && !lease->hostname)
318
/* If a machine turns up on a new net without dropping the old lease,
319
or two machines claim the same name, then we end up with two interfaces with
320
the same name. Check for that here and remove the name from the old lease. */
324
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
325
if (lease_tmp->hostname && hostname_isequal(lease_tmp->hostname, name))
327
new_name = lease_tmp->hostname;
328
lease_tmp->hostname = NULL;
331
new_fqdn = lease_tmp->fqdn;
332
lease_tmp->fqdn = NULL;
336
if (!new_name && (new_name = malloc(strlen(name) + 1)))
337
strcpy(new_name, name);
339
if (suffix && !new_fqdn && (new_fqdn = malloc(strlen(name) + strlen(suffix) + 2)))
341
strcpy(new_fqdn, name);
342
strcat(new_fqdn, ".");
343
strcat(new_fqdn, suffix);
348
free(lease->hostname);
352
lease->hostname = new_name;
353
lease->fqdn = new_fqdn;