2
0
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:
David Hankins
2007-05-08 23:05:22 +00:00
parent 74dc3e0b27
commit 98bd7ca099
112 changed files with 22575 additions and 17450 deletions

View File

@@ -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 (&lt, 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 (&lt, 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);