diff options
author | David Hankins <dhankins@isc.org> | 2007-05-08 23:05:22 +0000 |
---|---|---|
committer | David Hankins <dhankins@isc.org> | 2007-05-08 23:05:22 +0000 |
commit | 98bd7ca0990e6d88e3345d3bc966ebe8216691a7 (patch) | |
tree | c4437ca467e8f733d530170a5c445747b2defd68 /server/mdb.c | |
parent | 74dc3e0b2786c46956e7517398ae6f7c6dad52d7 (diff) | |
download | isc-dhcp-98bd7ca0990e6d88e3345d3bc966ebe8216691a7.tar.gz |
DHCPv6 branch merged to HEAD.
Diffstat (limited to 'server/mdb.c')
-rw-r--r-- | server/mdb.c | 254 |
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 (<, 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); |