mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-31 06:15:55 +00:00
DHCPv6 branch merged to HEAD.
This commit is contained in:
254
server/mdb.c
254
server/mdb.c
@@ -34,7 +34,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: mdb.c,v 1.88 2007/05/04 21:46:50 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: mdb.c,v 1.89 2007/05/08 23:05:22 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@@ -49,6 +49,25 @@ lease_id_hash_t *lease_uid_hash;
|
||||
lease_ip_hash_t *lease_ip_addr_hash;
|
||||
lease_id_hash_t *lease_hw_addr_hash;
|
||||
|
||||
/*
|
||||
* We allow users to specify any option as a host identifier.
|
||||
*
|
||||
* Any host is uniquely identified by the combination of
|
||||
* option type & option data.
|
||||
*
|
||||
* We expect people will only use a few types of options as host
|
||||
* identifier. Because of this, we store a list with an entry for
|
||||
* each option type. Each of these has a hash table, which contains
|
||||
* hash of the option data.
|
||||
*/
|
||||
typedef struct host_id_info {
|
||||
struct option *option;
|
||||
host_hash_t *values_hash;
|
||||
struct host_id_info *next;
|
||||
} host_id_info_t;
|
||||
|
||||
static host_id_info_t *host_id_info = NULL;
|
||||
|
||||
int numclasseswritten;
|
||||
|
||||
omapi_object_type_t *dhcp_type_host;
|
||||
@@ -129,6 +148,79 @@ static int find_uid_statement (struct executable_statement *esp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static host_id_info_t *
|
||||
find_host_id_info(unsigned int option_code) {
|
||||
host_id_info_t *p;
|
||||
|
||||
for (p=host_id_info; p != NULL; p = p->next) {
|
||||
if (p->option->code == option_code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Debugging code */
|
||||
#if 0
|
||||
isc_result_t
|
||||
print_host(const void *name, unsigned len, void *value) {
|
||||
struct host_decl *h;
|
||||
printf("--------------\n");
|
||||
printf("name:'%s'\n", print_hex_1(len, name, 60));
|
||||
printf("len:%d\n", len);
|
||||
h = (struct host_decl *)value;
|
||||
printf("host @%p is '%s'\n", h, h->name);
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
hash_print_hosts(struct hash_table *h) {
|
||||
hash_foreach(h, print_host);
|
||||
printf("--------------\n");
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
void
|
||||
change_host_uid(struct host_decl *host, const char *uid, int len) {
|
||||
struct host_decl *old_entry;
|
||||
|
||||
/* XXX: should consolidate this type of code throughout */
|
||||
if (host_uid_hash == NULL) {
|
||||
if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) {
|
||||
log_fatal("Can't allocate host/uid hash");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the old entry, if one exists.
|
||||
*/
|
||||
if (host->client_identifier.data != NULL) {
|
||||
host_hash_delete(host_uid_hash,
|
||||
host->client_identifier.data,
|
||||
host->client_identifier.len,
|
||||
MDL);
|
||||
data_string_forget(&host->client_identifier, MDL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set our new value.
|
||||
*/
|
||||
memset(&host->client_identifier, 0, sizeof(host->client_identifier));
|
||||
host->client_identifier.len = len;
|
||||
if (!buffer_allocate(&host->client_identifier.buffer, len, MDL)) {
|
||||
log_fatal("Can't allocate uid buffer");
|
||||
}
|
||||
host->client_identifier.data = host->client_identifier.buffer->data;
|
||||
memcpy((char *)host->client_identifier.data, uid, len);
|
||||
|
||||
/*
|
||||
* And add to hash.
|
||||
*/
|
||||
host_hash_add(host_uid_hash, host->client_identifier.data,
|
||||
host->client_identifier.len, host, MDL);
|
||||
}
|
||||
|
||||
isc_result_t enter_host (hd, dynamicp, commit)
|
||||
struct host_decl *hd;
|
||||
int dynamicp;
|
||||
@@ -137,6 +229,7 @@ isc_result_t enter_host (hd, dynamicp, commit)
|
||||
struct host_decl *hp = (struct host_decl *)0;
|
||||
struct host_decl *np = (struct host_decl *)0;
|
||||
struct executable_statement *esp;
|
||||
host_id_info_t *h_id_info;
|
||||
|
||||
if (!host_name_hash) {
|
||||
if (!host_new_hash(&host_name_hash, HOST_HASH_SIZE, MDL))
|
||||
@@ -276,6 +369,63 @@ isc_result_t enter_host (hd, dynamicp, commit)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we use an option as our host identifier, record it here.
|
||||
*/
|
||||
if (hd->host_id_option != NULL) {
|
||||
/*
|
||||
* Look for the host identifier information for this option,
|
||||
* and create a new entry if there is none.
|
||||
*/
|
||||
h_id_info = find_host_id_info(hd->host_id_option->code);
|
||||
if (h_id_info == NULL) {
|
||||
h_id_info = dmalloc(sizeof(*h_id_info), MDL);
|
||||
if (h_id_info == NULL) {
|
||||
log_fatal("No memory for host-identifier "
|
||||
"option information.");
|
||||
}
|
||||
option_reference(&h_id_info->option,
|
||||
hd->host_id_option, MDL);
|
||||
if (!host_new_hash(&h_id_info->values_hash,
|
||||
HOST_HASH_SIZE, MDL)) {
|
||||
log_fatal("No memory for host-identifer "
|
||||
"option hash.");
|
||||
}
|
||||
h_id_info->next = host_id_info;
|
||||
host_id_info = h_id_info;
|
||||
}
|
||||
|
||||
if (host_hash_lookup(&hp, h_id_info->values_hash,
|
||||
hd->host_id.data, hd->host_id.len, MDL)) {
|
||||
/*
|
||||
* If this option is already present, then add
|
||||
* this host to the list in n_ipaddr, unless
|
||||
* we have already done so previously.
|
||||
*
|
||||
* XXXSK: This seems scary to me, but I don't
|
||||
* fully understand how these are used.
|
||||
* Shouldn't there be multiple lists, or
|
||||
* maybe we should just forbid duplicates?
|
||||
*/
|
||||
if (np == NULL) {
|
||||
np = hp;
|
||||
while (np->n_ipaddr != NULL) {
|
||||
np = np->n_ipaddr;
|
||||
}
|
||||
if (hd != np) {
|
||||
host_reference(&np->n_ipaddr, hd, MDL);
|
||||
}
|
||||
}
|
||||
host_dereference(&hp, MDL);
|
||||
} else {
|
||||
host_hash_add(h_id_info->values_hash,
|
||||
hd->host_id.data,
|
||||
hd->host_id.len,
|
||||
hd, MDL);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamicp && commit) {
|
||||
if (!write_host (hd))
|
||||
return ISC_R_IOERROR;
|
||||
@@ -409,6 +559,11 @@ isc_result_t delete_host (hd, commit)
|
||||
}
|
||||
}
|
||||
|
||||
if (hd->host_id_option != NULL) {
|
||||
option_dereference(&hd->host_id_option, MDL);
|
||||
data_string_forget(&hd->host_id, MDL);
|
||||
}
|
||||
|
||||
if (hd -> n_ipaddr) {
|
||||
if (uid_head && hd -> n_ipaddr -> client_identifier.len) {
|
||||
host_hash_add
|
||||
@@ -470,6 +625,43 @@ int find_hosts_by_uid (struct host_decl **hp,
|
||||
return host_hash_lookup (hp, host_uid_hash, data, len, file, line);
|
||||
}
|
||||
|
||||
int
|
||||
find_hosts_by_option(struct host_decl **hp,
|
||||
struct packet *packet,
|
||||
struct option_state *opt_state,
|
||||
const char *file, int line) {
|
||||
host_id_info_t *p;
|
||||
struct option_cache *oc;
|
||||
struct data_string data;
|
||||
int found;
|
||||
|
||||
for (p = host_id_info; p != NULL; p = p->next) {
|
||||
oc = lookup_option(p->option->universe,
|
||||
opt_state, p->option->code);
|
||||
if (oc != NULL) {
|
||||
memset(&data, 0, sizeof(data));
|
||||
if (!evaluate_option_cache(&data, packet, NULL, NULL,
|
||||
opt_state, NULL,
|
||||
&global_scope, oc,
|
||||
MDL)) {
|
||||
log_error("Error evaluating option cache");
|
||||
return 0;
|
||||
}
|
||||
|
||||
found = host_hash_lookup(hp, p->values_hash,
|
||||
data.data, data.len,
|
||||
file, line);
|
||||
|
||||
data_string_forget(&data, MDL);
|
||||
|
||||
if (found) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* More than one host_decl can be returned by find_hosts_by_haddr or
|
||||
find_hosts_by_uid, and each host_decl can have multiple addresses.
|
||||
Loop through the list of hosts, and then for each host, through the
|
||||
@@ -688,29 +880,29 @@ int find_grouped_subnet (struct subnet **sp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int subnet_inner_than (subnet, scan, warnp)
|
||||
struct subnet *subnet, *scan;
|
||||
int warnp;
|
||||
{
|
||||
if (addr_eq (subnet_number (subnet -> net, scan -> netmask),
|
||||
scan -> net) ||
|
||||
addr_eq (subnet_number (scan -> net, subnet -> netmask),
|
||||
subnet -> net)) {
|
||||
char n1buf [16];
|
||||
/* XXX: could speed up if everyone had a prefix length */
|
||||
int
|
||||
subnet_inner_than(const struct subnet *subnet,
|
||||
const struct subnet *scan,
|
||||
int warnp) {
|
||||
if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
|
||||
addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
|
||||
char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")];
|
||||
int i, j;
|
||||
for (i = 0; i < 32; i++)
|
||||
if (subnet -> netmask.iabuf [3 - (i >> 3)]
|
||||
for (i = 0; i < 128; i++)
|
||||
if (subnet->netmask.iabuf[3 - (i >> 3)]
|
||||
& (1 << (i & 7)))
|
||||
break;
|
||||
for (j = 0; j < 32; j++)
|
||||
if (scan -> netmask.iabuf [3 - (j >> 3)] &
|
||||
for (j = 0; j < 128; j++)
|
||||
if (scan->netmask.iabuf[3 - (j >> 3)] &
|
||||
(1 << (j & 7)))
|
||||
break;
|
||||
strcpy (n1buf, piaddr (subnet -> net));
|
||||
if (warnp)
|
||||
log_error ("%ssubnet %s/%d overlaps subnet %s/%d",
|
||||
"Warning: ", n1buf, 32 - i,
|
||||
piaddr (scan -> net), 32 - j);
|
||||
if (warnp) {
|
||||
strcpy(n1buf, piaddr(subnet->net));
|
||||
log_error("Warning: subnet %s/%d overlaps subnet %s/%d",
|
||||
n1buf, 32 - i,
|
||||
piaddr(scan->net), 32 - j);
|
||||
}
|
||||
if (i < j)
|
||||
return 1;
|
||||
}
|
||||
@@ -1053,7 +1245,7 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate)
|
||||
just_move_it:
|
||||
#if defined (FAILOVER_PROTOCOL)
|
||||
/* Atsfp should be cleared upon any state change that implies
|
||||
* propogation wether supersede_lease was given a copy lease
|
||||
* propogation whether supersede_lease was given a copy lease
|
||||
* structure or not (often from the pool_timer()).
|
||||
*/
|
||||
if (propogate)
|
||||
@@ -1234,7 +1426,7 @@ void make_binding_state_transition (struct lease *lease)
|
||||
lease -> binding_state == FTS_ACTIVE &&
|
||||
lease -> next_binding_state != FTS_RELEASED))) {
|
||||
#if defined (NSUPDATE)
|
||||
ddns_removals (lease);
|
||||
ddns_removals(lease, NULL);
|
||||
#endif
|
||||
if (lease -> on_expiry) {
|
||||
execute_statements ((struct binding_value **)0,
|
||||
@@ -1285,7 +1477,7 @@ void make_binding_state_transition (struct lease *lease)
|
||||
lease -> binding_state == FTS_ACTIVE &&
|
||||
lease -> next_binding_state == FTS_RELEASED))) {
|
||||
#if defined (NSUPDATE)
|
||||
ddns_removals (lease);
|
||||
ddns_removals(lease, NULL);
|
||||
#endif
|
||||
if (lease -> on_release) {
|
||||
execute_statements ((struct binding_value **)0,
|
||||
@@ -1452,7 +1644,7 @@ void release_lease (lease, packet)
|
||||
/* If there are statements to execute when the lease is
|
||||
released, execute them. */
|
||||
#if defined (NSUPDATE)
|
||||
ddns_removals (lease);
|
||||
ddns_removals(lease, NULL);
|
||||
#endif
|
||||
if (lease -> on_release) {
|
||||
execute_statements ((struct binding_value **)0,
|
||||
@@ -1513,7 +1705,7 @@ void abandon_lease (lease, message)
|
||||
{
|
||||
struct lease *lt = (struct lease *)0;
|
||||
#if defined (NSUPDATE)
|
||||
ddns_removals (lease);
|
||||
ddns_removals(lease, NULL);
|
||||
#endif
|
||||
|
||||
if (!lease_copy (<, lease, MDL))
|
||||
@@ -1545,7 +1737,7 @@ void dissociate_lease (lease)
|
||||
{
|
||||
struct lease *lt = (struct lease *)0;
|
||||
#if defined (NSUPDATE)
|
||||
ddns_removals (lease);
|
||||
ddns_removals(lease, NULL);
|
||||
#endif
|
||||
|
||||
if (!lease_copy (<, lease, MDL))
|
||||
@@ -2102,6 +2294,9 @@ int write_leases ()
|
||||
}
|
||||
}
|
||||
log_info ("Wrote %d leases to leases file.", num_written);
|
||||
if (!write_leases6()) {
|
||||
return 0;
|
||||
}
|
||||
if (!commit_leases ())
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -2470,6 +2665,15 @@ void free_everything ()
|
||||
if (dns_zone_hash)
|
||||
dns_zone_free_hash_table (&dns_zone_hash, MDL);
|
||||
dns_zone_hash = 0;
|
||||
|
||||
while (host_id_info != NULL) {
|
||||
host_id_info_t *tmp;
|
||||
option_dereference(&host_id_info->option, MDL);
|
||||
host_free_hash_table(&host_id_info->values_hash, MDL);
|
||||
tmp = host_id_info->next;
|
||||
dfree(host_id_info, MDL);
|
||||
host_id_info = tmp;
|
||||
}
|
||||
#if 0
|
||||
if (auth_key_hash)
|
||||
auth_key_free_hash_table (&auth_key_hash, MDL);
|
||||
|
Reference in New Issue
Block a user