summaryrefslogtreecommitdiff
path: root/server/mdb.c
diff options
context:
space:
mode:
authorDavid Hankins <dhankins@isc.org>2007-05-08 23:05:22 +0000
committerDavid Hankins <dhankins@isc.org>2007-05-08 23:05:22 +0000
commit98bd7ca0990e6d88e3345d3bc966ebe8216691a7 (patch)
treec4437ca467e8f733d530170a5c445747b2defd68 /server/mdb.c
parent74dc3e0b2786c46956e7517398ae6f7c6dad52d7 (diff)
downloadisc-dhcp-98bd7ca0990e6d88e3345d3bc966ebe8216691a7.tar.gz
DHCPv6 branch merged to HEAD.
Diffstat (limited to 'server/mdb.c')
-rw-r--r--server/mdb.c254
1 files changed, 229 insertions, 25 deletions
diff --git a/server/mdb.c b/server/mdb.c
index 910c72dc..536407dd 100644
--- a/server/mdb.c
+++ b/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 (&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);