mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.0.tar.gz
This commit is contained in:
323
src/lease.c
Normal file
323
src/lease.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct dhcp_lease *leases;
|
||||
FILE *lease_file;
|
||||
int dns_dirty, file_dirty;
|
||||
|
||||
int lease_init(char *filename, char *domain, char *buff,
|
||||
char *buff2, time_t now, struct dhcp_config *dhcp_configs)
|
||||
{
|
||||
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3;
|
||||
unsigned long ei;
|
||||
time_t expires;
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
struct in_addr addr;
|
||||
struct dhcp_lease *lease;
|
||||
struct dhcp_config *config;
|
||||
int clid_len = 0;
|
||||
int has_old = 0;
|
||||
|
||||
leases = NULL;
|
||||
|
||||
if (!(lease_file = fopen(filename, "a+")))
|
||||
die("cannot open or create leases file: %s", NULL);
|
||||
|
||||
rewind(lease_file); /* file opened with mode a+ which sets pointer at end. */
|
||||
|
||||
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %256s %500s",
|
||||
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, buff, buff2) == 13)
|
||||
{
|
||||
/* strictly time_t is opaque, but this hack should work on all sane systems,
|
||||
even when sizeof(time_t) == 8 */
|
||||
expires = (time_t)ei;
|
||||
|
||||
if (ei != 0 && difftime(now, expires) > 0)
|
||||
{
|
||||
has_old = 1;
|
||||
continue; /* expired */
|
||||
}
|
||||
|
||||
hwaddr[0] = e0;
|
||||
hwaddr[1] = e1;
|
||||
hwaddr[2] = e2;
|
||||
hwaddr[3] = e3;
|
||||
hwaddr[4] = e4;
|
||||
hwaddr[5] = e5;
|
||||
|
||||
addr.s_addr = htonl((a0<<24) + (a1<<16) + (a2<<8) + a3);
|
||||
|
||||
/* decode hex in place */
|
||||
if (strcmp(buff2, "*") == 0)
|
||||
clid_len = 0;
|
||||
else
|
||||
{
|
||||
int s = (strlen(buff2)/3) + 1;
|
||||
for (clid_len = 0; clid_len < s; clid_len++)
|
||||
{
|
||||
buff2[(clid_len*3)+2] = 0;
|
||||
buff2[clid_len] = strtol(&buff2[clid_len*3], NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lease = lease_allocate(buff2, clid_len, addr)))
|
||||
die ("cannot get memory", NULL);
|
||||
|
||||
lease->expires = expires;
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
|
||||
if (strcmp(buff, "*") != 0)
|
||||
lease_set_hostname(lease, buff, domain);
|
||||
}
|
||||
|
||||
dns_dirty = 1;
|
||||
file_dirty = has_old;
|
||||
|
||||
/* Deal with edits to the config file which may have changed the hostname
|
||||
associated with a hardware address. Do this after the main loop so that
|
||||
changes get written back out */
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
|
||||
(config->hostname))
|
||||
lease_set_hostname(lease, config->hostname, domain);
|
||||
|
||||
return fileno(lease_file);
|
||||
}
|
||||
|
||||
void lease_update_dns(int force_dns)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
int i;
|
||||
|
||||
if (file_dirty)
|
||||
{
|
||||
rewind(lease_file);
|
||||
ftruncate(fileno(lease_file), 0);
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
fprintf(lease_file, "%lu %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s ",
|
||||
(unsigned long)lease->expires, lease->hwaddr[0], lease->hwaddr[1],
|
||||
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||
lease->hwaddr[5], inet_ntoa(lease->addr),
|
||||
lease->hostname ? lease->hostname : "*");
|
||||
|
||||
if (lease->clid_len)
|
||||
{
|
||||
for (i = 0; i < lease->clid_len - 1; i++)
|
||||
fprintf(lease_file, "%.2x:", lease->clid[i]);
|
||||
fprintf(lease_file, "%.2x\n", lease->clid[i]);
|
||||
}
|
||||
else
|
||||
fprintf(lease_file, "*\n");
|
||||
|
||||
}
|
||||
|
||||
fflush(lease_file);
|
||||
fsync(fileno(lease_file));
|
||||
file_dirty = 0;
|
||||
|
||||
}
|
||||
|
||||
if (dns_dirty || force_dns)
|
||||
{
|
||||
cache_unhash_dhcp();
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
{
|
||||
if (lease->fqdn)
|
||||
{
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE);
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, 0);
|
||||
}
|
||||
else if (lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, F_REVERSE);
|
||||
}
|
||||
|
||||
dns_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease, *tmp, **up;
|
||||
|
||||
for (lease = leases, up = &leases; lease; lease = tmp)
|
||||
{
|
||||
tmp = lease->next;
|
||||
if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
|
||||
{
|
||||
file_dirty = 1;
|
||||
|
||||
*up = lease->next; /* unlink */
|
||||
if (lease->hostname)
|
||||
{
|
||||
free(lease->hostname);
|
||||
dns_dirty = 1;
|
||||
}
|
||||
if (lease->fqdn)
|
||||
free(lease->fqdn);
|
||||
if (lease->clid)
|
||||
free(lease->clid);
|
||||
free(lease);
|
||||
}
|
||||
else
|
||||
up = &lease->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len)
|
||||
{
|
||||
/* zero length means clid from hwaddr: never match am option clid to
|
||||
a hardware-address derived clid */
|
||||
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (clid_len)
|
||||
{
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->clid && clid_len == lease->clid_len &&
|
||||
memcmp(clid, lease->clid, clid_len) == 0)
|
||||
return lease;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (!lease->clid &&
|
||||
memcmp(clid, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
||||
return lease;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->addr.s_addr == addr.s_addr)
|
||||
return lease;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
if (!(lease = malloc(sizeof(struct dhcp_lease))))
|
||||
return NULL;
|
||||
|
||||
lease->clid = NULL;
|
||||
lease->clid_len = clid_len;
|
||||
|
||||
if (clid_len)
|
||||
{
|
||||
if (!(lease->clid = malloc(clid_len)))
|
||||
{
|
||||
free(lease);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(lease->clid, clid, clid_len);
|
||||
}
|
||||
|
||||
lease->hostname = lease->fqdn = NULL;
|
||||
lease->addr = addr;
|
||||
memset(lease->hwaddr, 0, ETHER_ADDR_LEN);
|
||||
lease->expires = 1;
|
||||
|
||||
lease->next = leases;
|
||||
leases = lease;
|
||||
|
||||
file_dirty = 1;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
void lease_set_expires(struct dhcp_lease *lease, time_t exp)
|
||||
{
|
||||
if (exp != lease->expires)
|
||||
file_dirty = dns_dirty = 1;
|
||||
|
||||
lease->expires = exp;
|
||||
}
|
||||
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr)
|
||||
{
|
||||
if (memcmp(lease->hwaddr, hwaddr, ETHER_ADDR_LEN) != 0)
|
||||
{
|
||||
file_dirty = 1;
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
|
||||
{
|
||||
struct dhcp_lease *lease_tmp;
|
||||
char *new_name = NULL, *new_fqdn = NULL;
|
||||
|
||||
if (lease->hostname && name && strcmp(lease->hostname, name) == 0)
|
||||
return;
|
||||
|
||||
if (!name && !lease->hostname)
|
||||
return;
|
||||
|
||||
/* If a machine turns up on a new net without dropping the old lease,
|
||||
or two machines claim the same name, then we end up with two interfaces with
|
||||
the same name. Check for that here and remove the name from the old lease. */
|
||||
|
||||
if (name)
|
||||
{
|
||||
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
|
||||
if (lease_tmp->hostname && hostname_isequal(lease_tmp->hostname, name))
|
||||
{
|
||||
new_name = lease_tmp->hostname;
|
||||
lease_tmp->hostname = NULL;
|
||||
if (lease_tmp->fqdn)
|
||||
{
|
||||
new_fqdn = lease_tmp->fqdn;
|
||||
lease_tmp->fqdn = NULL;
|
||||
}
|
||||
}
|
||||
if (!new_name)
|
||||
{
|
||||
new_name = malloc(strlen(name) + 1);
|
||||
strcpy(new_name, name);
|
||||
}
|
||||
if (suffix && !new_fqdn)
|
||||
{
|
||||
new_fqdn = malloc(strlen(name) + strlen(suffix) + 2);
|
||||
strcpy(new_fqdn, name);
|
||||
strcat(new_fqdn, ".");
|
||||
strcat(new_fqdn, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (lease->hostname)
|
||||
free(lease->hostname);
|
||||
if (lease->fqdn)
|
||||
free(lease->fqdn);
|
||||
|
||||
lease->hostname = new_name;
|
||||
lease->fqdn = new_fqdn;
|
||||
|
||||
file_dirty = dns_dirty = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user