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: clparse.c,v 1.68 2007/01/29 10:25:54 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
"$Id: clparse.c,v 1.69 2007/05/08 23:05:20 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -54,6 +54,11 @@ u_int32_t default_requested_options [] = {
0
};
static void parse_client_default_duid(struct parse *cfile);
static void parse_client6_lease_statement(struct parse *cfile);
static struct dhc6_ia *parse_client6_ia_statement(struct parse *cfile);
static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
/* client-conf-file :== client-declarations END_OF_FILE
client-declarations :== <nil>
| client-declaration
@@ -66,9 +71,6 @@ isc_result_t read_client_conf ()
struct interface_info *ip;
isc_result_t status;
/* Set up the initial dhcp option universe. */
initialize_common_option_spaces ();
/* Initialize the top level client configuration. */
memset (&top_level_config, 0, sizeof top_level_config);
@@ -84,6 +86,9 @@ isc_result_t read_client_conf ()
top_level_config.requested_options = default_requested_options;
top_level_config.omapi_port = -1;
top_level_config.do_forward_update = 1;
/* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
*/
top_level_config.requested_lease = 7200;
group_allocate (&top_level_config.on_receipt, MDL);
if (!top_level_config.on_receipt)
@@ -200,13 +205,25 @@ void read_client_leases ()
token = next_token (&val, (unsigned *)0, cfile);
if (token == END_OF_FILE)
break;
if (token != LEASE) {
switch (token) {
case DEFAULT_DUID:
parse_client_default_duid(cfile);
break;
case LEASE:
parse_client_lease_statement(cfile, 0);
break;
case LEASE6:
parse_client6_lease_statement(cfile);
break;
default:
log_error ("Corrupt lease file - possible data loss!");
skip_to_semi (cfile);
break;
} else
parse_client_lease_statement (cfile, 0);
}
} while (1);
end_parse (&cfile);
@@ -825,7 +842,7 @@ void make_client_config (client, config)
}
/* client-lease-statement :==
RBRACE client-lease-declarations LBRACE
LBRACE client-lease-declarations RBRACE
client-lease-declarations :==
<nil> |
@@ -1071,6 +1088,505 @@ void parse_client_lease_declaration (cfile, lease, ipp, clientp)
}
}
/* Parse a default-duid ""; statement.
*/
static void
parse_client_default_duid(struct parse *cfile)
{
struct data_string new_duid;
const char *val = NULL;
unsigned len;
int token;
memset(&new_duid, 0, sizeof(new_duid));
token = next_token(&val, &len, cfile);
if (token != STRING) {
parse_warn(cfile, "Expected DUID string.");
skip_to_semi(cfile);
return;
}
if (len <= 2) {
parse_warn(cfile, "Invalid DUID contents.");
skip_to_semi(cfile);
return;
}
if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
parse_warn(cfile, "Out of memory parsing default DUID.");
skip_to_semi(cfile);
return;
}
new_duid.data = new_duid.buffer->data;
new_duid.len = len;
memcpy(new_duid.buffer->data, val, len);
/* Rotate the last entry into place. */
if (default_duid.buffer != NULL)
data_string_forget(&default_duid, MDL);
data_string_copy(&default_duid, &new_duid, MDL);
data_string_forget(&new_duid, MDL);
parse_semi(cfile);
}
/* Parse a lease6 {} construct. The v6 client is a little different
* than the v4 client today, in that it only retains one lease, the
* active lease, and discards any less recent information. It may
* be useful in the future to cache additional information, but it
* is not worth the effort for the moment.
*/
static void
parse_client6_lease_statement(struct parse *cfile)
{
struct option_cache *oc = NULL;
struct dhc6_lease *lease;
struct dhc6_ia **ia;
struct client_state *client = NULL;
struct interface_info *iface = NULL;
struct data_string ds;
const char *val;
unsigned len;
int token, has_ia, no_semi, has_name;
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly brace.");
skip_to_semi(cfile);
return;
}
lease = dmalloc(sizeof(*lease), MDL);
if (lease == NULL) {
parse_warn(cfile, "Unable to allocate lease state.");
skip_to_rbrace(cfile, 1);
return;
}
option_state_allocate(&lease->options, MDL);
if (lease->options == NULL) {
parse_warn(cfile, "Unable to allocate option cache.");
skip_to_rbrace(cfile, 1);
dfree(lease, MDL);
return;
}
has_ia = 0;
has_name = 0;
ia = &lease->bindings;
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch(token) {
case IA_NA:
*ia = parse_client6_ia_statement(cfile);
if (*ia != NULL) {
ia = &(*ia)->next;
has_ia = 1;
}
no_semi = 1;
break;
case INTERFACE:
if (iface != NULL) {
parse_warn(cfile, "Multiple interface names?");
skip_to_semi(cfile);
no_semi = 1;
break;
}
token = next_token(&val, &len, cfile);
if (token != STRING) {
strerror:
parse_warn(cfile, "Expecting a string.");
skip_to_semi(cfile);
no_semi = 1;
break;
}
for (iface = interfaces ; iface != NULL ;
iface = iface->next) {
if (strcmp(iface->name, val) == 0)
break;
}
if (iface == NULL) {
parse_warn(cfile, "Unknown interface.");
break;
}
break;
case NAME:
has_name = 1;
if (client != NULL) {
parse_warn(cfile, "Multiple state names?");
skip_to_semi(cfile);
no_semi = 1;
break;
}
if (iface == NULL) {
parse_warn(cfile, "Client name without "
"interface.");
skip_to_semi(cfile);
no_semi = 1;
break;
}
token = next_token(&val, &len, cfile);
if (token != STRING)
goto strerror;
for (client = iface->client ; client != NULL ;
client = client->next) {
if ((client->name != NULL) &&
(strcmp(client->name, val) == 0))
break;
}
if (client == NULL) {
parse_warn(cfile, "Unknown client state %s.",
val);
break;
}
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
lease->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token, %s.", val);
no_semi = 1;
skip_to_semi(cfile);
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
if (!has_ia) {
log_debug("Lease with no IA's discarded from lease db.");
dhc6_lease_destroy(lease, MDL);
return;
}
if (iface == NULL)
parse_warn(cfile, "Lease has no interface designation.");
if (!has_name && (client == NULL)) {
for (client = iface->client ; client != NULL ;
client = client->next) {
if (client->name == NULL)
break;
}
}
if (client == NULL) {
parse_warn(cfile, "No matching client state.");
dhc6_lease_destroy(lease, MDL);
return;
}
/* Fetch Preference option from option cache. */
memset(&ds, 0, sizeof(ds));
oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
if ((oc != NULL) &&
evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
NULL, &global_scope, oc, MDL)) {
if (ds.len != 1) {
log_error("Invalid length of DHCPv6 Preference option "
"(%d != 1)", ds.len);
data_string_forget(&ds, MDL);
dhc6_lease_destroy(lease, MDL);
return;
} else
lease->pref = ds.data[0];
data_string_forget(&ds, MDL);
}
/* Fetch server-id option from option cache. */
oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
if ((oc == NULL) ||
!evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
lease->options, NULL, &global_scope, oc,
MDL) ||
(lease->server_id.len == 0)) {
/* This should be impossible... */
log_error("Invalid SERVERID option cache.");
dhc6_lease_destroy(lease, MDL);
return;
}
if (client->active_lease != NULL)
dhc6_lease_destroy(client->active_lease, MDL);
client->active_lease = lease;
}
/* Parse an ia_na object from the client lease.
*/
static struct dhc6_ia *
parse_client6_ia_statement(struct parse *cfile)
{
struct data_string id;
struct option_cache *oc = NULL;
struct dhc6_ia *ia;
struct dhc6_addr **addr;
const char *val;
unsigned len;
int token, no_semi;
ia = dmalloc(sizeof(*ia), MDL);
if (ia == NULL) {
parse_warn(cfile, "Out of memory allocating IA_NA state.");
skip_to_semi(cfile);
return NULL;
}
/* Get IAID. */
memset(&id, 0, sizeof(id));
if (parse_cshl(&id, cfile)) {
if (id.len == 4)
memcpy(ia->iaid, id.data, 4);
else {
parse_warn(cfile, "Expecting IAID of length 4, got %d.",
id.len);
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
data_string_forget(&id, MDL);
} else {
parse_warn(cfile, "Expecting IAID.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly brace.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
option_state_allocate(&ia->options, MDL);
if (ia->options == NULL) {
parse_warn(cfile, "Unable to allocate option state.");
skip_to_rbrace(cfile, 1);
dfree(ia, MDL);
return NULL;
}
addr = &ia->addrs;
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch (token) {
case STARTS:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->starts = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case RENEW:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->renew = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case REBIND:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->rebind = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case IAADDR:
*addr = parse_client6_iaaddr_statement(cfile);
if (*addr != NULL)
addr = &(*addr)->next;
no_semi = 1;
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
ia->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token.");
no_semi = 1;
skip_to_semi(cfile);
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
return ia;
}
/* Parse an iaaddr {} structure. */
static struct dhc6_addr *
parse_client6_iaaddr_statement(struct parse *cfile)
{
struct option_cache *oc = NULL;
struct dhc6_addr *addr;
const char *val;
int token, no_semi;
addr = dmalloc(sizeof(*addr), MDL);
if (addr == NULL) {
parse_warn(cfile, "Unable to allocate IAADDR state.");
skip_to_semi(cfile);
return NULL;
}
/* Get IP address. */
if (!parse_ip6_addr(cfile, &addr->address)) {
skip_to_semi(cfile);
dfree(addr, MDL);
return NULL;
}
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly bracket.");
skip_to_semi(cfile);
dfree(addr, MDL);
return NULL;
}
option_state_allocate(&addr->options, MDL);
if (addr->options == NULL) {
parse_warn(cfile, "Unable to allocate option state.");
skip_to_semi(cfile);
dfree(addr, MDL);
return NULL;
}
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch (token) {
case STARTS:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
addr->starts = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case PREFERRED_LIFE:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
addr->preferred_life = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case MAX_LIFE:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
addr->max_life = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
addr->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token.");
skip_to_rbrace(cfile, 1);
no_semi = 1;
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
return addr;
}
void parse_string_list (cfile, lp, multiple)
struct parse *cfile;
struct string_list **lp;