mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-28 21:07:43 +00:00
-n [master]
26510 Add support for classes in the IPv6 code
This commit is contained in:
parent
a7341359cc
commit
01fa619fab
3
RELNOTES
3
RELNOTES
@ -72,6 +72,9 @@ work on other platforms. Please report any problems and suggested fixes to
|
|||||||
- Add support in v6 for on-commit, on-expire and on-release.
|
- Add support in v6 for on-commit, on-expire and on-release.
|
||||||
[ISC-Bugs #27912
|
[ISC-Bugs #27912
|
||||||
|
|
||||||
|
- Add support for using classes with v6.
|
||||||
|
[ISC-Bugs #26510]
|
||||||
|
|
||||||
Changes since 4.2.5
|
Changes since 4.2.5
|
||||||
|
|
||||||
- Address static analysis warnings.
|
- Address static analysis warnings.
|
||||||
|
@ -1231,6 +1231,8 @@ intern(char *atom, enum dhcp_token dfv) {
|
|||||||
return PACKET;
|
return PACKET;
|
||||||
if (!strcasecmp (atom + 1, "ool"))
|
if (!strcasecmp (atom + 1, "ool"))
|
||||||
return POOL;
|
return POOL;
|
||||||
|
if (!strcasecmp (atom + 1, "ool6"))
|
||||||
|
return POOL6;
|
||||||
if (!strcasecmp (atom + 1, "refix6"))
|
if (!strcasecmp (atom + 1, "refix6"))
|
||||||
return PREFIX6;
|
return PREFIX6;
|
||||||
if (!strcasecmp (atom + 1, "seudo"))
|
if (!strcasecmp (atom + 1, "seudo"))
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
* ``http://www.nominum.com''.
|
* ``http://www.nominum.com''.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \file includes/dhcpd.h */
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef __CYGWIN32__
|
#ifndef __CYGWIN32__
|
||||||
@ -933,9 +935,7 @@ struct shared_network {
|
|||||||
struct subnet *subnets;
|
struct subnet *subnets;
|
||||||
struct interface_info *interface;
|
struct interface_info *interface;
|
||||||
struct pool *pools;
|
struct pool *pools;
|
||||||
struct ipv6_pool **ipv6_pools; /* NULL-terminated array */
|
struct ipv6_pond *ipv6_pond;
|
||||||
int last_ipv6_pool; /* offset of last IPv6 pool
|
|
||||||
used to issue a lease */
|
|
||||||
struct group *group;
|
struct group *group;
|
||||||
#if defined (FAILOVER_PROTOCOL)
|
#if defined (FAILOVER_PROTOCOL)
|
||||||
dhcp_failover_state_t *failover_peer;
|
dhcp_failover_state_t *failover_peer;
|
||||||
@ -1530,6 +1530,26 @@ extern ia_hash_t *ia_na_active;
|
|||||||
extern ia_hash_t *ia_ta_active;
|
extern ia_hash_t *ia_ta_active;
|
||||||
extern ia_hash_t *ia_pd_active;
|
extern ia_hash_t *ia_pd_active;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief ipv6_pool structure
|
||||||
|
*
|
||||||
|
* This structure is part of a range of addresses or prefixes.
|
||||||
|
* A range6 or prefix6 statement will map to one or more of these
|
||||||
|
* with each pool being a simple block of the form xxxx/yyy and
|
||||||
|
* all the pools adding up to comprise the entire range. When
|
||||||
|
* choosing an address or prefix the code will walk through the
|
||||||
|
* pools until it finds one that is available.
|
||||||
|
*
|
||||||
|
* The naming for this structure is unfortunate as there is also
|
||||||
|
* a v4 pool structure and the two are not equivalent. The v4
|
||||||
|
* pool matches the ipv6_pond structure. I considered changing the
|
||||||
|
* name of this structure but concluded that doing so would be worse
|
||||||
|
* than leaving it as is. Changing it adds some risk and makes for
|
||||||
|
* larger differences between the 4.1 & 4.2 code and the 4.3 code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
struct ipv6_pool {
|
struct ipv6_pool {
|
||||||
int refcnt; /* reference count */
|
int refcnt; /* reference count */
|
||||||
u_int16_t pool_type; /* IA_xx */
|
u_int16_t pool_type; /* IA_xx */
|
||||||
@ -1545,6 +1565,34 @@ struct ipv6_pool {
|
|||||||
struct shared_network *shared_network; /* shared_network for
|
struct shared_network *shared_network; /* shared_network for
|
||||||
this pool */
|
this pool */
|
||||||
struct subnet *subnet; /* subnet for this pool */
|
struct subnet *subnet; /* subnet for this pool */
|
||||||
|
struct ipv6_pond *ipv6_pond; /* pond for this pool */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief ipv6_pond structure
|
||||||
|
*
|
||||||
|
* This structure is the ipv6 version of the v4 pool structure.
|
||||||
|
* It contains the address and prefix information via the pointers
|
||||||
|
* to the ipv6_pools and the allowability of this pool for a given
|
||||||
|
* client via the permit lists and the valid TIMEs.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ipv6_pond {
|
||||||
|
int refcnt;
|
||||||
|
struct ipv6_pond *next;
|
||||||
|
struct group *group;
|
||||||
|
struct shared_network *shared_network; /* backpointer to the enclosing
|
||||||
|
shared network */
|
||||||
|
struct permit *permit_list; /* allow clients from this list */
|
||||||
|
struct permit *prohibit_list; /* deny clients from this list */
|
||||||
|
TIME valid_from; /* deny pool use before this date */
|
||||||
|
TIME valid_until; /* deny pool use after this date */
|
||||||
|
|
||||||
|
struct ipv6_pool **ipv6_pools; /* NULL-terminated array */
|
||||||
|
int last_ipv6_pool; /* offset of last IPv6 pool
|
||||||
|
used to issue a lease */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags and state for dhcp_ddns_cb_t */
|
/* Flags and state for dhcp_ddns_cb_t */
|
||||||
@ -1945,14 +1993,17 @@ int parse_ip6_addr_expr(struct expression **, struct parse *);
|
|||||||
int parse_ip6_prefix(struct parse *, struct iaddr *, u_int8_t *);
|
int parse_ip6_prefix(struct parse *, struct iaddr *, u_int8_t *);
|
||||||
void parse_address_range (struct parse *, struct group *, int,
|
void parse_address_range (struct parse *, struct group *, int,
|
||||||
struct pool *, struct lease **);
|
struct pool *, struct lease **);
|
||||||
void parse_address_range6(struct parse *cfile, struct group *group);
|
void parse_address_range6(struct parse *cfile, struct group *group,
|
||||||
void parse_prefix6(struct parse *cfile, struct group *group);
|
struct ipv6_pond *);
|
||||||
|
void parse_prefix6(struct parse *cfile, struct group *group,
|
||||||
|
struct ipv6_pond *);
|
||||||
void parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl);
|
void parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl);
|
||||||
void parse_ia_na_declaration(struct parse *);
|
void parse_ia_na_declaration(struct parse *);
|
||||||
void parse_ia_ta_declaration(struct parse *);
|
void parse_ia_ta_declaration(struct parse *);
|
||||||
void parse_ia_pd_declaration(struct parse *);
|
void parse_ia_pd_declaration(struct parse *);
|
||||||
void parse_server_duid(struct parse *cfile);
|
void parse_server_duid(struct parse *cfile);
|
||||||
void parse_server_duid_conf(struct parse *cfile);
|
void parse_server_duid_conf(struct parse *cfile);
|
||||||
|
void parse_pool6_statement (struct parse *, struct group *, int);
|
||||||
|
|
||||||
/* ddns.c */
|
/* ddns.c */
|
||||||
int ddns_updates(struct packet *, struct lease *, struct lease *,
|
int ddns_updates(struct packet *, struct lease *, struct lease *,
|
||||||
@ -3549,6 +3600,13 @@ isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
|
|||||||
const struct in6_addr *addr);
|
const struct in6_addr *addr);
|
||||||
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr,
|
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr,
|
||||||
const struct ipv6_pool *pool);
|
const struct ipv6_pool *pool);
|
||||||
|
isc_result_t ipv6_pond_allocate(struct ipv6_pond **pond,
|
||||||
|
const char *file, int line);
|
||||||
|
isc_result_t ipv6_pond_reference(struct ipv6_pond **pond,
|
||||||
|
struct ipv6_pond *src,
|
||||||
|
const char *file, int line);
|
||||||
|
isc_result_t ipv6_pond_dereference(struct ipv6_pond **pond,
|
||||||
|
const char *file, int line);
|
||||||
|
|
||||||
isc_result_t renew_leases(struct ia_xx *ia);
|
isc_result_t renew_leases(struct ia_xx *ia);
|
||||||
isc_result_t release_leases(struct ia_xx *ia);
|
isc_result_t release_leases(struct ia_xx *ia);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Tokens for config file lexer and parser. */
|
Tokens for config file lexer and parser. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC")
|
* Copyright (c) 2011-2013 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
* Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC")
|
* Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
* Copyright (c) 1996-2003 by Internet Software Consortium
|
* Copyright (c) 1996-2003 by Internet Software Consortium
|
||||||
*
|
*
|
||||||
@ -365,7 +365,8 @@ enum dhcp_token {
|
|||||||
GETHOSTBYNAME = 665,
|
GETHOSTBYNAME = 665,
|
||||||
PRIMARY6 = 666,
|
PRIMARY6 = 666,
|
||||||
SECONDARY6 = 667,
|
SECONDARY6 = 667,
|
||||||
TOKEN_INFINIBAND = 668
|
TOKEN_INFINIBAND = 668,
|
||||||
|
POOL6 = 669
|
||||||
};
|
};
|
||||||
|
|
||||||
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
|
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
|
||||||
|
@ -32,10 +32,11 @@
|
|||||||
* ``http://www.nominum.com''.
|
* ``http://www.nominum.com''.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \file server/confpars.c */
|
||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
|
|
||||||
static unsigned char global_host_once = 1;
|
static unsigned char global_host_once = 1;
|
||||||
static unsigned char dhcpv6_class_once = 1;
|
|
||||||
|
|
||||||
static int parse_binding_value(struct parse *cfile,
|
static int parse_binding_value(struct parse *cfile,
|
||||||
struct binding_value *value);
|
struct binding_value *value);
|
||||||
@ -634,7 +635,7 @@ int parse_statement (cfile, group, type, host_decl, declaration)
|
|||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return declaration;
|
return declaration;
|
||||||
}
|
}
|
||||||
parse_address_range6(cfile, group);
|
parse_address_range6(cfile, group, NULL);
|
||||||
return declaration;
|
return declaration;
|
||||||
|
|
||||||
case PREFIX6:
|
case PREFIX6:
|
||||||
@ -645,7 +646,7 @@ int parse_statement (cfile, group, type, host_decl, declaration)
|
|||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return declaration;
|
return declaration;
|
||||||
}
|
}
|
||||||
parse_prefix6(cfile, group);
|
parse_prefix6(cfile, group, NULL);
|
||||||
return declaration;
|
return declaration;
|
||||||
|
|
||||||
case FIXED_PREFIX6:
|
case FIXED_PREFIX6:
|
||||||
@ -660,6 +661,19 @@ int parse_statement (cfile, group, type, host_decl, declaration)
|
|||||||
parse_fixed_prefix6(cfile, host_decl);
|
parse_fixed_prefix6(cfile, host_decl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case POOL6:
|
||||||
|
skip_token(&val, NULL, cfile);
|
||||||
|
if (type == POOL_DECL) {
|
||||||
|
parse_warn (cfile, "pool declared within pool.");
|
||||||
|
skip_to_semi(cfile);
|
||||||
|
} else if (type != SUBNET_DECL) {
|
||||||
|
parse_warn (cfile, "pool declared outside of network");
|
||||||
|
skip_to_semi(cfile);
|
||||||
|
} else
|
||||||
|
parse_pool6_statement (cfile, group, type);
|
||||||
|
|
||||||
|
return declaration;
|
||||||
|
|
||||||
#endif /* DHCPv6 */
|
#endif /* DHCPv6 */
|
||||||
|
|
||||||
case TOKEN_NOT:
|
case TOKEN_NOT:
|
||||||
@ -1377,6 +1391,163 @@ void parse_failover_state (cfile, state, stos)
|
|||||||
}
|
}
|
||||||
#endif /* defined (FAILOVER_PROTOCOL) */
|
#endif /* defined (FAILOVER_PROTOCOL) */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief Parse allow and deny statements
|
||||||
|
*
|
||||||
|
* This function handles the common processing code for permit and deny
|
||||||
|
* statements in the parse_pool_statement and parse_pool6_statement functions.
|
||||||
|
* It reads in the configuration and constructs a new permit structure that it
|
||||||
|
* attachs to the permit_head passed in from the caller.
|
||||||
|
*
|
||||||
|
* The allow or deny token should already be consumed, this function expects
|
||||||
|
* one of the following:
|
||||||
|
* known-clients;
|
||||||
|
* unknown-clients;
|
||||||
|
* known clients;
|
||||||
|
* unknown clients;
|
||||||
|
* authenticated clients;
|
||||||
|
* unauthenticated clients;
|
||||||
|
* all clients;
|
||||||
|
* dynamic bootp clients;
|
||||||
|
* members of <class name>;
|
||||||
|
* after <date>;
|
||||||
|
*
|
||||||
|
* \param[in] cfile = the configuration file being parsed
|
||||||
|
* \param[in] permit_head = the head of the permit list (permit or prohibit)
|
||||||
|
* to which to attach the newly created permit structure
|
||||||
|
* \param[in] is_allow = 1 if this is being invoked for an allow statement
|
||||||
|
* = 0 if this is being invoked for a deny statement
|
||||||
|
* \param[in] valid_from = pointers to the time values from the enclosing pool
|
||||||
|
* \param[in] valid_until or pond structure. One of them will be filled in if
|
||||||
|
* the configuration includes an "after" clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
void get_permit(cfile, permit_head, is_allow, valid_from, valid_until)
|
||||||
|
struct parse *cfile;
|
||||||
|
struct permit **permit_head;
|
||||||
|
int is_allow;
|
||||||
|
TIME *valid_from, *valid_until;
|
||||||
|
{
|
||||||
|
enum dhcp_token token;
|
||||||
|
struct permit *permit;
|
||||||
|
const char *val;
|
||||||
|
int need_clients = 1;
|
||||||
|
TIME t;
|
||||||
|
|
||||||
|
/* Create our permit structure */
|
||||||
|
permit = new_permit(MDL);
|
||||||
|
if (!permit)
|
||||||
|
log_fatal ("no memory for permit");
|
||||||
|
|
||||||
|
token = next_token(&val, NULL, cfile);
|
||||||
|
switch (token) {
|
||||||
|
case UNKNOWN:
|
||||||
|
permit->type = permit_unknown_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KNOWN_CLIENTS:
|
||||||
|
need_clients = 0;
|
||||||
|
permit->type = permit_known_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNKNOWN_CLIENTS:
|
||||||
|
need_clients = 0;
|
||||||
|
permit->type = permit_unknown_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KNOWN:
|
||||||
|
permit->type = permit_known_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUTHENTICATED:
|
||||||
|
permit->type = permit_authenticated_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNAUTHENTICATED:
|
||||||
|
permit->type = permit_unauthenticated_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ALL:
|
||||||
|
permit->type = permit_all_clients;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DYNAMIC:
|
||||||
|
permit->type = permit_dynamic_bootp_clients;
|
||||||
|
if (next_token (&val, NULL, cfile) != TOKEN_BOOTP) {
|
||||||
|
parse_warn (cfile, "expecting \"bootp\"");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
free_permit (permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MEMBERS:
|
||||||
|
need_clients = 0;
|
||||||
|
if (next_token (&val, NULL, cfile) != OF) {
|
||||||
|
parse_warn (cfile, "expecting \"of\"");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
free_permit (permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (next_token (&val, NULL, cfile) != STRING) {
|
||||||
|
parse_warn (cfile, "expecting class name.");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
free_permit (permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
permit->type = permit_class;
|
||||||
|
permit->class = NULL;
|
||||||
|
find_class(&permit->class, val, MDL);
|
||||||
|
if (!permit->class)
|
||||||
|
parse_warn(cfile, "no such class: %s", val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AFTER:
|
||||||
|
need_clients = 0;
|
||||||
|
if (*valid_from || *valid_until) {
|
||||||
|
parse_warn(cfile, "duplicate \"after\" clause.");
|
||||||
|
skip_to_semi(cfile);
|
||||||
|
free_permit(permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = parse_date_core(cfile);
|
||||||
|
permit->type = permit_after;
|
||||||
|
permit->after = t;
|
||||||
|
if (is_allow) {
|
||||||
|
*valid_from = t;
|
||||||
|
} else {
|
||||||
|
*valid_until = t;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
parse_warn (cfile, "expecting permit type.");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
free_permit (permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The need_clients flag is set if we are expecting the
|
||||||
|
* CLIENTS token
|
||||||
|
*/
|
||||||
|
if ((need_clients != 0) &&
|
||||||
|
(next_token (&val, NULL, cfile) != CLIENTS)) {
|
||||||
|
parse_warn (cfile, "expecting \"clients\"");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
free_permit (permit, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*permit_head)
|
||||||
|
permit_head = &((*permit_head)->next);
|
||||||
|
*permit_head = permit;
|
||||||
|
parse_semi (cfile);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Permit_list_match returns 1 if every element of the permit list in lhs
|
/* Permit_list_match returns 1 if every element of the permit list in lhs
|
||||||
also appears in rhs. Note that this doesn't by itself mean that the
|
also appears in rhs. Note that this doesn't by itself mean that the
|
||||||
two lists are equal - to check for equality, permit_list_match has to
|
two lists are equal - to check for equality, permit_list_match has to
|
||||||
@ -1407,6 +1578,25 @@ int permit_list_match (struct permit *lhs, struct permit *rhs)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief Parse a pool statement
|
||||||
|
*
|
||||||
|
* Pool statements are used to group declarations and permit & deny information
|
||||||
|
* with a specific address range. They must be declared within a shared network
|
||||||
|
* or subnet and there may be multiple pools withing a shared network or subnet.
|
||||||
|
* Each pool may have a different set of permit or deny options.
|
||||||
|
*
|
||||||
|
* \param[in] cfile = the configuration file being parsed
|
||||||
|
* \param[in] group = the group structure for this pool
|
||||||
|
* \param[in] type = the type of the enclosing statement. This must be
|
||||||
|
* SHARED_NET_DECL or SUBNET_DECL for this function.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* void - This function either parses the statement and updates the structures
|
||||||
|
* or it generates an error message and possible halts the program if
|
||||||
|
* it encounters a problem.
|
||||||
|
*/
|
||||||
void parse_pool_statement (cfile, group, type)
|
void parse_pool_statement (cfile, group, type)
|
||||||
struct parse *cfile;
|
struct parse *cfile;
|
||||||
struct group *group;
|
struct group *group;
|
||||||
@ -1416,15 +1606,11 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
const char *val;
|
const char *val;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
struct pool *pool, **p, *pp;
|
struct pool *pool, **p, *pp;
|
||||||
struct permit *permit;
|
|
||||||
struct permit **permit_head;
|
|
||||||
int declaration = 0;
|
int declaration = 0;
|
||||||
isc_result_t status;
|
isc_result_t status;
|
||||||
struct lease *lpchain = (struct lease *)0, *lp;
|
struct lease *lpchain = NULL, *lp;
|
||||||
TIME t;
|
|
||||||
int is_allow = 0;
|
|
||||||
|
|
||||||
pool = (struct pool *)0;
|
pool = NULL;
|
||||||
status = pool_allocate(&pool, MDL);
|
status = pool_allocate(&pool, MDL);
|
||||||
if (status != ISC_R_SUCCESS)
|
if (status != ISC_R_SUCCESS)
|
||||||
log_fatal ("no memory for pool: %s",
|
log_fatal ("no memory for pool: %s",
|
||||||
@ -1462,14 +1648,13 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
token = peek_token (&val, (unsigned *)0, cfile);
|
token = peek_token(&val, NULL, cfile);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case TOKEN_NO:
|
case TOKEN_NO:
|
||||||
skip_token(&val, (unsigned *)0, cfile);
|
skip_token(&val, NULL, cfile);
|
||||||
token = next_token (&val, (unsigned *)0, cfile);
|
token = next_token(&val, NULL, cfile);
|
||||||
if (token != FAILOVER ||
|
if (token != FAILOVER ||
|
||||||
(token = next_token (&val, (unsigned *)0,
|
(token = next_token(&val, NULL, cfile)) != PEER) {
|
||||||
cfile)) != PEER) {
|
|
||||||
parse_warn(cfile,
|
parse_warn(cfile,
|
||||||
"expecting \"failover peer\".");
|
"expecting \"failover peer\".");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
@ -1484,14 +1669,14 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
|
|
||||||
#if defined (FAILOVER_PROTOCOL)
|
#if defined (FAILOVER_PROTOCOL)
|
||||||
case FAILOVER:
|
case FAILOVER:
|
||||||
skip_token(&val, (unsigned *)0, cfile);
|
skip_token(&val, NULL, cfile);
|
||||||
token = next_token (&val, (unsigned *)0, cfile);
|
token = next_token (&val, NULL, cfile);
|
||||||
if (token != PEER) {
|
if (token != PEER) {
|
||||||
parse_warn(cfile, "expecting 'peer'.");
|
parse_warn(cfile, "expecting 'peer'.");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
token = next_token (&val, (unsigned *)0, cfile);
|
token = next_token(&val, NULL, cfile);
|
||||||
if (token != STRING) {
|
if (token != STRING) {
|
||||||
parse_warn(cfile, "expecting string.");
|
parse_warn(cfile, "expecting string.");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
@ -1513,133 +1698,24 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case RANGE:
|
case RANGE:
|
||||||
skip_token(&val, (unsigned *)0, cfile);
|
skip_token(&val, NULL, cfile);
|
||||||
parse_address_range (cfile, group, type,
|
parse_address_range (cfile, group, type,
|
||||||
pool, &lpchain);
|
pool, &lpchain);
|
||||||
break;
|
break;
|
||||||
case ALLOW:
|
case ALLOW:
|
||||||
permit_head = &pool -> permit_list;
|
skip_token(&val, NULL, cfile);
|
||||||
/* remember the clause which leads to get_permit */
|
get_permit(cfile, &pool->permit_list, 1,
|
||||||
is_allow = 1;
|
&pool->valid_from, &pool->valid_until);
|
||||||
get_permit:
|
|
||||||
permit = new_permit (MDL);
|
|
||||||
if (!permit)
|
|
||||||
log_fatal ("no memory for permit");
|
|
||||||
skip_token(&val, (unsigned *)0, cfile);
|
|
||||||
token = next_token (&val, (unsigned *)0, cfile);
|
|
||||||
switch (token) {
|
|
||||||
case UNKNOWN:
|
|
||||||
permit -> type = permit_unknown_clients;
|
|
||||||
get_clients:
|
|
||||||
if (next_token (&val, (unsigned *)0,
|
|
||||||
cfile) != CLIENTS) {
|
|
||||||
parse_warn (cfile,
|
|
||||||
"expecting \"clients\"");
|
|
||||||
skip_to_semi (cfile);
|
|
||||||
free_permit (permit, MDL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KNOWN_CLIENTS:
|
|
||||||
permit -> type = permit_known_clients;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UNKNOWN_CLIENTS:
|
|
||||||
permit -> type = permit_unknown_clients;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KNOWN:
|
|
||||||
permit -> type = permit_known_clients;
|
|
||||||
goto get_clients;
|
|
||||||
|
|
||||||
case AUTHENTICATED:
|
|
||||||
permit -> type = permit_authenticated_clients;
|
|
||||||
goto get_clients;
|
|
||||||
|
|
||||||
case UNAUTHENTICATED:
|
|
||||||
permit -> type =
|
|
||||||
permit_unauthenticated_clients;
|
|
||||||
goto get_clients;
|
|
||||||
|
|
||||||
case ALL:
|
|
||||||
permit -> type = permit_all_clients;
|
|
||||||
goto get_clients;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DYNAMIC:
|
|
||||||
permit -> type = permit_dynamic_bootp_clients;
|
|
||||||
if (next_token (&val, (unsigned *)0,
|
|
||||||
cfile) != TOKEN_BOOTP) {
|
|
||||||
parse_warn (cfile,
|
|
||||||
"expecting \"bootp\"");
|
|
||||||
skip_to_semi (cfile);
|
|
||||||
free_permit (permit, MDL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
goto get_clients;
|
|
||||||
|
|
||||||
case MEMBERS:
|
|
||||||
if (next_token (&val, (unsigned *)0,
|
|
||||||
cfile) != OF) {
|
|
||||||
parse_warn (cfile, "expecting \"of\"");
|
|
||||||
skip_to_semi (cfile);
|
|
||||||
free_permit (permit, MDL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (next_token (&val, (unsigned *)0,
|
|
||||||
cfile) != STRING) {
|
|
||||||
parse_warn (cfile,
|
|
||||||
"expecting class name.");
|
|
||||||
skip_to_semi (cfile);
|
|
||||||
free_permit (permit, MDL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
permit -> type = permit_class;
|
|
||||||
permit -> class = (struct class *)0;
|
|
||||||
find_class (&permit -> class, val, MDL);
|
|
||||||
if (!permit -> class)
|
|
||||||
parse_warn (cfile,
|
|
||||||
"no such class: %s", val);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AFTER:
|
|
||||||
if (pool->valid_from || pool->valid_until) {
|
|
||||||
parse_warn(cfile,
|
|
||||||
"duplicate \"after\" clause.");
|
|
||||||
skip_to_semi(cfile);
|
|
||||||
free_permit(permit, MDL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
t = parse_date_core(cfile);
|
|
||||||
permit->type = permit_after;
|
|
||||||
permit->after = t;
|
|
||||||
if (is_allow) {
|
|
||||||
pool->valid_from = t;
|
|
||||||
} else {
|
|
||||||
pool->valid_until = t;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
parse_warn (cfile, "expecting permit type.");
|
|
||||||
skip_to_semi (cfile);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (*permit_head)
|
|
||||||
permit_head = &((*permit_head) -> next);
|
|
||||||
*permit_head = permit;
|
|
||||||
parse_semi (cfile);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DENY:
|
case DENY:
|
||||||
permit_head = &pool -> prohibit_list;
|
skip_token(&val, NULL, cfile);
|
||||||
/* remember the clause which leads to get_permit */
|
get_permit(cfile, &pool->prohibit_list, 0,
|
||||||
is_allow = 0;
|
&pool->valid_from, &pool->valid_until);
|
||||||
goto get_permit;
|
break;
|
||||||
|
|
||||||
case RBRACE:
|
case RBRACE:
|
||||||
skip_token(&val, (unsigned *)0, cfile);
|
skip_token(&val, NULL, cfile);
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1654,8 +1730,7 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
declaration = parse_statement(cfile, pool->group,
|
declaration = parse_statement(cfile, pool->group,
|
||||||
POOL_DECL,
|
POOL_DECL, NULL,
|
||||||
(struct host_decl *)0,
|
|
||||||
declaration);
|
declaration);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1707,7 +1782,7 @@ void parse_pool_statement (cfile, group, type)
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
/* Dereference the lease chain. */
|
/* Dereference the lease chain. */
|
||||||
lp = (struct lease *)0;
|
lp = NULL;
|
||||||
while (lpchain) {
|
while (lpchain) {
|
||||||
lease_reference(&lp, lpchain, MDL);
|
lease_reference(&lp, lpchain, MDL);
|
||||||
lease_dereference(&lpchain, MDL);
|
lease_dereference(&lpchain, MDL);
|
||||||
@ -2008,12 +2083,6 @@ int parse_class_declaration (cp, cfile, group, type)
|
|||||||
int submatchedonce = 0;
|
int submatchedonce = 0;
|
||||||
unsigned code;
|
unsigned code;
|
||||||
|
|
||||||
if (dhcpv6_class_once && local_family == AF_INET6) {
|
|
||||||
dhcpv6_class_once = 0;
|
|
||||||
log_error("WARNING: class declarations are not supported "
|
|
||||||
"for DHCPv6.");
|
|
||||||
}
|
|
||||||
|
|
||||||
token = next_token (&val, NULL, cfile);
|
token = next_token (&val, NULL, cfile);
|
||||||
if (token != STRING) {
|
if (token != STRING) {
|
||||||
parse_warn (cfile, "Expecting class name");
|
parse_warn (cfile, "Expecting class name");
|
||||||
@ -3688,15 +3757,13 @@ void parse_address_range (cfile, group, type, inpool, lpchain)
|
|||||||
#ifdef DHCPv6
|
#ifdef DHCPv6
|
||||||
static void
|
static void
|
||||||
add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
|
add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
|
||||||
struct iaddr *lo_addr, int bits, int units) {
|
struct iaddr *lo_addr, int bits, int units,
|
||||||
|
struct ipv6_pond *pond) {
|
||||||
struct ipv6_pool *pool;
|
struct ipv6_pool *pool;
|
||||||
struct shared_network *share;
|
|
||||||
struct in6_addr tmp_in6_addr;
|
struct in6_addr tmp_in6_addr;
|
||||||
int num_pools;
|
int num_pools;
|
||||||
struct ipv6_pool **tmp;
|
struct ipv6_pool **tmp;
|
||||||
|
|
||||||
share = subnet->shared_network;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create our pool.
|
* Create our pool.
|
||||||
*/
|
*/
|
||||||
@ -3724,16 +3791,19 @@ add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
|
|||||||
pool->subnet = NULL;
|
pool->subnet = NULL;
|
||||||
subnet_reference(&pool->subnet, subnet, MDL);
|
subnet_reference(&pool->subnet, subnet, MDL);
|
||||||
pool->shared_network = NULL;
|
pool->shared_network = NULL;
|
||||||
shared_network_reference(&pool->shared_network, share, MDL);
|
shared_network_reference(&pool->shared_network,
|
||||||
|
subnet->shared_network, MDL);
|
||||||
|
pool->ipv6_pond = NULL;
|
||||||
|
ipv6_pond_reference(&pool->ipv6_pond, pond, MDL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Increase our array size for ipv6_pools in the shared_network.
|
* Increase our array size for ipv6_pools in the pond
|
||||||
*/
|
*/
|
||||||
if (share->ipv6_pools == NULL) {
|
if (pond->ipv6_pools == NULL) {
|
||||||
num_pools = 0;
|
num_pools = 0;
|
||||||
} else {
|
} else {
|
||||||
num_pools = 0;
|
num_pools = 0;
|
||||||
while (share->ipv6_pools[num_pools] != NULL) {
|
while (pond->ipv6_pools[num_pools] != NULL) {
|
||||||
num_pools++;
|
num_pools++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3742,34 +3812,114 @@ add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
|
|||||||
log_fatal("Out of memory");
|
log_fatal("Out of memory");
|
||||||
}
|
}
|
||||||
if (num_pools > 0) {
|
if (num_pools > 0) {
|
||||||
memcpy(tmp, share->ipv6_pools,
|
memcpy(tmp, pond->ipv6_pools,
|
||||||
sizeof(struct ipv6_pool *) * num_pools);
|
sizeof(struct ipv6_pool *) * num_pools);
|
||||||
}
|
}
|
||||||
if (share->ipv6_pools != NULL) {
|
if (pond->ipv6_pools != NULL) {
|
||||||
dfree(share->ipv6_pools, MDL);
|
dfree(pond->ipv6_pools, MDL);
|
||||||
}
|
}
|
||||||
share->ipv6_pools = tmp;
|
pond->ipv6_pools = tmp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record this pool in our array of pools for this shared network.
|
* Record this pool in our array of pools for this shared network.
|
||||||
*/
|
*/
|
||||||
ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
|
ipv6_pool_reference(&pond->ipv6_pools[num_pools], pool, MDL);
|
||||||
share->ipv6_pools[num_pools+1] = NULL;
|
pond->ipv6_pools[num_pools+1] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief Find or create a default pond
|
||||||
|
*
|
||||||
|
* Find or create an ipv6_pond on which to attach the ipv6_pools. We
|
||||||
|
* check the shared network to see if there is a general purpose
|
||||||
|
* entry - this will have an empty prohibit list and a permit list
|
||||||
|
* with a single entry that permits all clients. If the shared
|
||||||
|
* network doesn't have one of them create it and attach it to
|
||||||
|
* the shared network and the return argument.
|
||||||
|
*
|
||||||
|
* This function is used when we have a range6 or prefix6 statement
|
||||||
|
* inside a subnet6 statement but outside of a pool6 statement.
|
||||||
|
* This routine constructs the missing ipv6_pond structure so
|
||||||
|
* we always have
|
||||||
|
* shared_network -> ipv6_pond -> ipv6_pool
|
||||||
|
*
|
||||||
|
* \param[in] group = a pointer to the group structure from which
|
||||||
|
* we can find the subnet and shared netowrk
|
||||||
|
* structures
|
||||||
|
* \param[out] ret_pond = a pointer to space for the pointer to
|
||||||
|
* the structure to return
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* void
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
add_ipv6_pond_to_network(struct group *group,
|
||||||
|
struct ipv6_pond **ret_pond) {
|
||||||
|
|
||||||
|
struct ipv6_pond *pond = NULL, *last = NULL;
|
||||||
|
struct permit *p;
|
||||||
|
isc_result_t status;
|
||||||
|
struct shared_network *shared = group->subnet->shared_network;
|
||||||
|
|
||||||
|
for (pond = shared->ipv6_pond; pond; pond = pond->next) {
|
||||||
|
if ((pond->group->statements == group->statements) &&
|
||||||
|
(pond->prohibit_list == NULL) &&
|
||||||
|
(pond->permit_list != NULL) &&
|
||||||
|
(pond->permit_list->next == NULL) &&
|
||||||
|
(pond->permit_list->type == permit_all_clients)) {
|
||||||
|
ipv6_pond_reference(ret_pond, pond, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last = pond;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no pond available, make one */
|
||||||
|
status = ipv6_pond_allocate(&pond, MDL);
|
||||||
|
if (status != ISC_R_SUCCESS)
|
||||||
|
log_fatal ("no memory for ad-hoc ipv6 pond: %s",
|
||||||
|
isc_result_totext (status));
|
||||||
|
p = new_permit (MDL);
|
||||||
|
if (p == NULL)
|
||||||
|
log_fatal ("no memory for ad-hoc ipv6 permit.");
|
||||||
|
|
||||||
|
/* we permit all clients */
|
||||||
|
p->type = permit_all_clients;
|
||||||
|
pond->permit_list = p;
|
||||||
|
|
||||||
|
/* and attach the pond to the return argument and the shared network */
|
||||||
|
ipv6_pond_reference(ret_pond, pond, MDL);
|
||||||
|
|
||||||
|
if (shared->ipv6_pond)
|
||||||
|
ipv6_pond_reference(&last->next, pond, MDL);
|
||||||
|
else
|
||||||
|
ipv6_pond_reference(&shared->ipv6_pond, pond, MDL);
|
||||||
|
|
||||||
|
shared_network_reference(&pond->shared_network, shared, MDL);
|
||||||
|
if (!clone_group (&pond->group, group, MDL))
|
||||||
|
log_fatal ("no memory for anon pool group.");
|
||||||
|
|
||||||
|
ipv6_pond_dereference(&pond, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* address-range6-declaration :== ip-address6 ip-address6 SEMI
|
/* address-range6-declaration :== ip-address6 ip-address6 SEMI
|
||||||
| ip-address6 SLASH number SEMI
|
| ip-address6 SLASH number SEMI
|
||||||
| ip-address6 [SLASH number] TEMPORARY SEMI */
|
| ip-address6 [SLASH number] TEMPORARY SEMI */
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_address_range6(struct parse *cfile, struct group *group) {
|
parse_address_range6(struct parse *cfile,
|
||||||
|
struct group *group,
|
||||||
|
struct ipv6_pond *inpond) {
|
||||||
struct iaddr lo, hi;
|
struct iaddr lo, hi;
|
||||||
int bits;
|
int bits;
|
||||||
enum dhcp_token token;
|
enum dhcp_token token;
|
||||||
const char *val;
|
const char *val;
|
||||||
struct iaddrcidrnetlist *nets;
|
struct iaddrcidrnetlist *nets, net;
|
||||||
struct iaddrcidrnetlist *p;
|
struct iaddrcidrnetlist *p;
|
||||||
u_int16_t type = D6O_IA_NA;
|
u_int16_t type = D6O_IA_NA;
|
||||||
|
struct ipv6_pond *pond = NULL;
|
||||||
|
|
||||||
if (local_family != AF_INET6) {
|
if (local_family != AF_INET6) {
|
||||||
parse_warn(cfile, "range6 statement is only supported "
|
parse_warn(cfile, "range6 statement is only supported "
|
||||||
@ -3789,6 +3939,12 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zero out the net entry in case we use it
|
||||||
|
*/
|
||||||
|
memset(&net, 0, sizeof(net));
|
||||||
|
net.cidrnet.lo_addr = lo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if we we're using range or CIDR notation or TEMPORARY
|
* See if we we're using range or CIDR notation or TEMPORARY
|
||||||
*/
|
*/
|
||||||
@ -3804,13 +3960,15 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bits = atoi(val);
|
net.cidrnet.bits = atoi(val);
|
||||||
|
bits = net.cidrnet.bits;
|
||||||
if ((bits < 0) || (bits > 128)) {
|
if ((bits < 0) || (bits > 128)) {
|
||||||
parse_warn(cfile, "networks have 0 to 128 bits");
|
parse_warn(cfile, "networks have 0 to 128 bits");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!is_cidr_mask_valid(&lo, bits)) {
|
|
||||||
|
if (!is_cidr_mask_valid(&net.cidrnet.lo_addr, bits)) {
|
||||||
parse_warn(cfile, "network mask too short");
|
parse_warn(cfile, "network mask too short");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return;
|
return;
|
||||||
@ -3829,8 +3987,7 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
type = D6O_IA_TA;
|
type = D6O_IA_TA;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ipv6_pool_to_subnet(group->subnet, type, &lo,
|
nets = &net;
|
||||||
bits, 128);
|
|
||||||
|
|
||||||
} else if (token == TEMPORARY) {
|
} else if (token == TEMPORARY) {
|
||||||
/*
|
/*
|
||||||
@ -3838,15 +3995,16 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
*/
|
*/
|
||||||
type = D6O_IA_TA;
|
type = D6O_IA_TA;
|
||||||
skip_token(NULL, NULL, cfile);
|
skip_token(NULL, NULL, cfile);
|
||||||
bits = 64;
|
net.cidrnet.bits = 64;
|
||||||
if (!is_cidr_mask_valid(&lo, bits)) {
|
if (!is_cidr_mask_valid(&net.cidrnet.lo_addr,
|
||||||
|
net.cidrnet.bits)) {
|
||||||
parse_warn(cfile, "network mask too short");
|
parse_warn(cfile, "network mask too short");
|
||||||
skip_to_semi(cfile);
|
skip_to_semi(cfile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ipv6_pool_to_subnet(group->subnet, type, &lo,
|
nets = &net;
|
||||||
bits, 128);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* No '/', so we are looking for the end address of
|
* No '/', so we are looking for the end address of
|
||||||
@ -3864,14 +4022,32 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
log_fatal("Error converting range to CIDR networks");
|
log_fatal("Error converting range to CIDR networks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we have a pond for this set of pools.
|
||||||
|
* If the caller supplied one we use it, otherwise
|
||||||
|
* check the shared network
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (inpond != NULL) {
|
||||||
|
ipv6_pond_reference(&pond, inpond, MDL);
|
||||||
|
} else {
|
||||||
|
add_ipv6_pond_to_network(group, &pond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that we have a pond add the nets we have parsed */
|
||||||
for (p=nets; p != NULL; p=p->next) {
|
for (p=nets; p != NULL; p=p->next) {
|
||||||
add_ipv6_pool_to_subnet(group->subnet, type,
|
add_ipv6_pool_to_subnet(group->subnet, type,
|
||||||
&p->cidrnet.lo_addr,
|
&p->cidrnet.lo_addr,
|
||||||
p->cidrnet.bits, 128);
|
p->cidrnet.bits, 128, pond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if we allocated a list free it now */
|
||||||
|
if (nets != &net)
|
||||||
free_iaddrcidrnetlist(&nets);
|
free_iaddrcidrnetlist(&nets);
|
||||||
}
|
|
||||||
|
ipv6_pond_dereference(&pond, MDL);
|
||||||
|
|
||||||
token = next_token(NULL, NULL, cfile);
|
token = next_token(NULL, NULL, cfile);
|
||||||
if (token != SEMI) {
|
if (token != SEMI) {
|
||||||
@ -3884,13 +4060,16 @@ parse_address_range6(struct parse *cfile, struct group *group) {
|
|||||||
/* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
|
/* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_prefix6(struct parse *cfile, struct group *group) {
|
parse_prefix6(struct parse *cfile,
|
||||||
|
struct group *group,
|
||||||
|
struct ipv6_pond *inpond) {
|
||||||
struct iaddr lo, hi;
|
struct iaddr lo, hi;
|
||||||
int bits;
|
int bits;
|
||||||
enum dhcp_token token;
|
enum dhcp_token token;
|
||||||
const char *val;
|
const char *val;
|
||||||
struct iaddrcidrnetlist *nets;
|
struct iaddrcidrnetlist *nets;
|
||||||
struct iaddrcidrnetlist *p;
|
struct iaddrcidrnetlist *p;
|
||||||
|
struct ipv6_pond *pond = NULL;
|
||||||
|
|
||||||
if (local_family != AF_INET6) {
|
if (local_family != AF_INET6) {
|
||||||
parse_warn(cfile, "prefix6 statement is only supported "
|
parse_warn(cfile, "prefix6 statement is only supported "
|
||||||
@ -3955,6 +4134,18 @@ parse_prefix6(struct parse *cfile, struct group *group) {
|
|||||||
log_fatal("Error converting prefix to CIDR");
|
log_fatal("Error converting prefix to CIDR");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we have a pond for this set of pools.
|
||||||
|
* If the caller supplied one we use it, otherwise
|
||||||
|
* check the shared network
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (inpond != NULL) {
|
||||||
|
ipv6_pond_reference(&pond, inpond, MDL);
|
||||||
|
} else {
|
||||||
|
add_ipv6_pond_to_network(group, &pond);
|
||||||
|
}
|
||||||
|
|
||||||
for (p = nets; p != NULL; p = p->next) {
|
for (p = nets; p != NULL; p = p->next) {
|
||||||
/* Normalize and check. */
|
/* Normalize and check. */
|
||||||
if (p->cidrnet.bits == 128) {
|
if (p->cidrnet.bits == 128) {
|
||||||
@ -3966,7 +4157,7 @@ parse_prefix6(struct parse *cfile, struct group *group) {
|
|||||||
}
|
}
|
||||||
add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
|
add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
|
||||||
&p->cidrnet.lo_addr,
|
&p->cidrnet.lo_addr,
|
||||||
p->cidrnet.bits, bits);
|
p->cidrnet.bits, bits, pond);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_iaddrcidrnetlist(&nets);
|
free_iaddrcidrnetlist(&nets);
|
||||||
@ -4052,6 +4243,141 @@ parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
|
|||||||
*h = ia;
|
*h = ia;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief Parse a pool6 statement
|
||||||
|
*
|
||||||
|
* Pool statements are used to group declarations and permit & deny information
|
||||||
|
* with a specific address range. They must be declared within a shared network
|
||||||
|
* or subnet and there may be multiple pools withing a shared network or subnet.
|
||||||
|
* Each pool may have a different set of permit or deny options.
|
||||||
|
*
|
||||||
|
* \param[in] cfile = the configuration file being parsed
|
||||||
|
* \param[in] group = the group structure for this pool
|
||||||
|
* \param[in] type = the type of the enclosing statement. This must be
|
||||||
|
* SUBNET_DECL for this function.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* void - This function either parses the statement and updates the structures
|
||||||
|
* or it generates an error message and possible halts the program if
|
||||||
|
* it encounters a problem.
|
||||||
|
*/
|
||||||
|
void parse_pool6_statement (cfile, group, type)
|
||||||
|
struct parse *cfile;
|
||||||
|
struct group *group;
|
||||||
|
int type;
|
||||||
|
{
|
||||||
|
enum dhcp_token token;
|
||||||
|
const char *val;
|
||||||
|
int done = 0;
|
||||||
|
struct ipv6_pond *pond, **p;
|
||||||
|
int declaration = 0;
|
||||||
|
isc_result_t status;
|
||||||
|
|
||||||
|
pond = NULL;
|
||||||
|
status = ipv6_pond_allocate(&pond, MDL);
|
||||||
|
if (status != ISC_R_SUCCESS)
|
||||||
|
log_fatal("no memory for pool6: %s",
|
||||||
|
isc_result_totext (status));
|
||||||
|
|
||||||
|
if (type == SUBNET_DECL)
|
||||||
|
shared_network_reference(&pond->shared_network,
|
||||||
|
group->subnet->shared_network,
|
||||||
|
MDL);
|
||||||
|
else {
|
||||||
|
parse_warn(cfile, "Dynamic pool6s are only valid inside "
|
||||||
|
"subnet statements.");
|
||||||
|
skip_to_semi(cfile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clone_group(&pond->group, group, MDL) == 0)
|
||||||
|
log_fatal("can't clone pool6 group.");
|
||||||
|
|
||||||
|
if (parse_lbrace(cfile) == 0) {
|
||||||
|
ipv6_pond_dereference(&pond, MDL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
token = peek_token(&val, NULL, cfile);
|
||||||
|
switch (token) {
|
||||||
|
case RANGE6:
|
||||||
|
skip_token(NULL, NULL, cfile);
|
||||||
|
parse_address_range6(cfile, group, pond);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PREFIX6:
|
||||||
|
skip_token(NULL, NULL, cfile);
|
||||||
|
parse_prefix6(cfile, group, pond);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ALLOW:
|
||||||
|
skip_token(NULL, NULL, cfile);
|
||||||
|
get_permit(cfile, &pond->permit_list, 1,
|
||||||
|
&pond->valid_from, &pond->valid_until);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DENY:
|
||||||
|
skip_token(NULL, NULL, cfile);
|
||||||
|
get_permit(cfile, &pond->prohibit_list, 0,
|
||||||
|
&pond->valid_from, &pond->valid_until);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RBRACE:
|
||||||
|
skip_token(&val, NULL, cfile);
|
||||||
|
done = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case END_OF_FILE:
|
||||||
|
/*
|
||||||
|
* We can get to END_OF_FILE if, for instance,
|
||||||
|
* the parse_statement() reads all available tokens
|
||||||
|
* and leaves us at the end.
|
||||||
|
*/
|
||||||
|
parse_warn(cfile, "unexpected end of file");
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
default:
|
||||||
|
declaration = parse_statement(cfile, pond->group,
|
||||||
|
POOL_DECL, NULL,
|
||||||
|
declaration);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (!done);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A possible optimization is to see if this pond can be merged into
|
||||||
|
* an already existing pond. But I'll pass on that for now as we need
|
||||||
|
* to repoint the leases to the other pond which is annoying. SAR
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add this pond to the list (will need updating if we add the
|
||||||
|
* optimization).
|
||||||
|
*/
|
||||||
|
|
||||||
|
p = &pond->shared_network->ipv6_pond;
|
||||||
|
for (; *p; p = &((*p)->next))
|
||||||
|
;
|
||||||
|
ipv6_pond_reference(p, pond, MDL);
|
||||||
|
|
||||||
|
/* Don't allow a pool6 declaration with no addresses or
|
||||||
|
prefixes, since it is probably a configuration error. */
|
||||||
|
if (pond->ipv6_pools == NULL) {
|
||||||
|
parse_warn (cfile, "Pool6 declaration with no %s.",
|
||||||
|
"address range6 or prefix6");
|
||||||
|
log_error ("Pool6 declarations must always contain at least");
|
||||||
|
log_error ("one range6 or prefix6 statement.");
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
ipv6_pond_dereference(&pond, MDL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* DHCPv6 */
|
#endif /* DHCPv6 */
|
||||||
|
|
||||||
/* allow-deny-keyword :== BOOTP
|
/* allow-deny-keyword :== BOOTP
|
||||||
|
@ -265,8 +265,8 @@ group {
|
|||||||
.SH ADDRESS POOLS
|
.SH ADDRESS POOLS
|
||||||
.PP
|
.PP
|
||||||
The
|
The
|
||||||
.B pool
|
\fBpool\fR and \fBpool6\fR
|
||||||
declaration can be used to specify a pool of addresses that will be
|
declarations can be used to specify a pool of addresses that will be
|
||||||
treated differently than another pool of addresses, even on the same
|
treated differently than another pool of addresses, even on the same
|
||||||
network segment or subnet. For example, you may want to provide a
|
network segment or subnet. For example, you may want to provide a
|
||||||
large set of addresses that can be assigned to DHCP clients that are
|
large set of addresses that can be assigned to DHCP clients that are
|
||||||
@ -316,6 +316,14 @@ deny list, then only those clients that do not match any entries on
|
|||||||
the deny list will be eligible. If both permit and deny lists exist
|
the deny list will be eligible. If both permit and deny lists exist
|
||||||
for a pool, then only clients that match the permit list and do not
|
for a pool, then only clients that match the permit list and do not
|
||||||
match the deny list will be allowed access.
|
match the deny list will be allowed access.
|
||||||
|
.PP
|
||||||
|
The \fBpool6\fR declaration is similar to the \fBpool6\fR declaration.
|
||||||
|
Currently it is only allowed within a \fBsubnet6\fR declaration, and
|
||||||
|
may not be included directly in a shared network declaration.
|
||||||
|
In addition to the \fBrange6\fR statement it allows the \fBprefix6\fR
|
||||||
|
statement to be included. You may include \fBrange6\fR statements
|
||||||
|
for both NA and TA and \fBprefixy6\fR statements in a single
|
||||||
|
\fBpool6\fR statement.
|
||||||
.SH DYNAMIC ADDRESS ALLOCATION
|
.SH DYNAMIC ADDRESS ALLOCATION
|
||||||
Address allocation is actually only done when a client is in the INIT
|
Address allocation is actually only done when a client is in the INIT
|
||||||
state and has sent a DHCPDISCOVER message. If the client thinks it
|
state and has sent a DHCPDISCOVER message. If the client thinks it
|
||||||
@ -442,7 +450,7 @@ this last method, change the "my state" line to:
|
|||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
.B failover peer "\fIname\fB" state {
|
.B failover peer "\fIname\fB" state {
|
||||||
.B my state partner-down;
|
.B my state partner-down;.
|
||||||
.B peer state \fIstate\fB at \fIdate\fB;
|
.B peer state \fIstate\fB at \fIdate\fB;
|
||||||
.B }
|
.B }
|
||||||
.fi
|
.fi
|
||||||
@ -894,6 +902,10 @@ total number of clients within a particular class or subclass that may
|
|||||||
hold leases at one time, and it is possible to specify automatic
|
hold leases at one time, and it is possible to specify automatic
|
||||||
subclassing based on the contents of the client packet.
|
subclassing based on the contents of the client packet.
|
||||||
.PP
|
.PP
|
||||||
|
Classing support for DHCPv6 clients was addded in 4.3.0. It follows
|
||||||
|
the same rules as for DHCPv4 except that support for billing classes
|
||||||
|
has not been added yet.
|
||||||
|
.PP
|
||||||
To add clients to classes based on conditional evaluation, you can
|
To add clients to classes based on conditional evaluation, you can
|
||||||
specify a matching expression in the class statement:
|
specify a matching expression in the class statement:
|
||||||
.PP
|
.PP
|
||||||
|
517
server/dhcpv6.c
517
server/dhcpv6.c
@ -14,6 +14,8 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \file server/dhcpv6.c */
|
||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
|
|
||||||
#ifdef DHCPv6
|
#ifdef DHCPv6
|
||||||
@ -989,59 +991,87 @@ try_client_v6_address(struct iasubopt **addr,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get an IPv6 address for the client.
|
/*!
|
||||||
*
|
*
|
||||||
* addr is the result (should be a pointer to NULL on entry)
|
* \brief Get an IPv6 address for the client.
|
||||||
* packet is the information about the packet from the client
|
*
|
||||||
* requested_iaaddr is a hint from the client
|
* Attempt to find a usable address for the client. We walk through
|
||||||
* client_id is the DUID for the client
|
* the ponds checking for permit and deny then through the pools
|
||||||
|
* seeing if they have an available address.
|
||||||
|
*
|
||||||
|
* \param reply = the state structure for the current work on this request
|
||||||
|
* if we create a lease we return it using reply->lease
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = we were able to find an address and are returning a
|
||||||
|
* pointer to the lease
|
||||||
|
* ISC_R_NORESOURCES = there don't appear to be any free addresses. This
|
||||||
|
* is probabalistic. We don't exhaustively try the
|
||||||
|
* address range, instead we hash the duid and if
|
||||||
|
* the address derived from the hash is in use we
|
||||||
|
* hash the address. After a number of failures we
|
||||||
|
* conclude the pool is basically full.
|
||||||
*/
|
*/
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network,
|
pick_v6_address(struct reply_state *reply)
|
||||||
const struct data_string *client_id)
|
|
||||||
{
|
{
|
||||||
struct ipv6_pool *p;
|
struct ipv6_pool *p = NULL;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
int i;
|
int i;
|
||||||
int start_pool;
|
int start_pool;
|
||||||
unsigned int attempts;
|
unsigned int attempts;
|
||||||
char tmp_buf[INET6_ADDRSTRLEN];
|
char tmp_buf[INET6_ADDRSTRLEN];
|
||||||
|
struct iasubopt **addr = &reply->lease;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No address pools, we're done.
|
* Do a quick walk through of the ponds and pools
|
||||||
|
* to see if we have any NA address pools
|
||||||
*/
|
*/
|
||||||
if (shared_network->ipv6_pools == NULL) {
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (pond->ipv6_pools == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
|
if (p->pool_type == D6O_IA_NA)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here and p is NULL we have no useful pools */
|
||||||
|
if (p == NULL) {
|
||||||
log_debug("Unable to pick client address: "
|
log_debug("Unable to pick client address: "
|
||||||
"no IPv6 pools on this shared network");
|
"no IPv6 pools on this shared network");
|
||||||
return ISC_R_NORESOURCES;
|
return ISC_R_NORESOURCES;
|
||||||
}
|
}
|
||||||
for (i = 0;; i++) {
|
|
||||||
p = shared_network->ipv6_pools[i];
|
|
||||||
if (p == NULL) {
|
|
||||||
log_debug("Unable to pick client address: "
|
|
||||||
"no IPv6 address pools "
|
|
||||||
"on this shared network");
|
|
||||||
return ISC_R_NORESOURCES;
|
|
||||||
}
|
|
||||||
if (p->pool_type == D6O_IA_NA) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise try to get a lease from the first subnet possible.
|
* We have at least one pool that could provide an address
|
||||||
|
* Now we walk through the ponds and pools again and check
|
||||||
|
* to see if the client is permitted and if an address is
|
||||||
|
* available
|
||||||
*
|
*
|
||||||
* We start looking at the last pool we allocated from, unless
|
* Within a given pond we start looking at the last pool we
|
||||||
* it had a collision trying to allocate an address. This will
|
* allocated from, unless it had a collision trying to allocate
|
||||||
* tend to move us into less-filled pools.
|
* an address. This will tend to move us into less-filled pools.
|
||||||
*/
|
*/
|
||||||
start_pool = shared_network->last_ipv6_pool;
|
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
start_pool = pond->last_ipv6_pool;
|
||||||
i = start_pool;
|
i = start_pool;
|
||||||
do {
|
do {
|
||||||
|
p = pond->ipv6_pools[i];
|
||||||
p = shared_network->ipv6_pools[i];
|
|
||||||
if ((p->pool_type == D6O_IA_NA) &&
|
if ((p->pool_type == D6O_IA_NA) &&
|
||||||
(create_lease6(p, addr, &attempts, client_id,
|
(create_lease6(p, addr, &attempts,
|
||||||
|
&reply->ia->iaid_duid,
|
||||||
cur_time + 120) == ISC_R_SUCCESS)) {
|
cur_time + 120) == ISC_R_SUCCESS)) {
|
||||||
/*
|
/*
|
||||||
* Record the pool used (or next one if there
|
* Record the pool used (or next one if there
|
||||||
@ -1049,23 +1079,24 @@ pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network,
|
|||||||
*/
|
*/
|
||||||
if (attempts > 1) {
|
if (attempts > 1) {
|
||||||
i++;
|
i++;
|
||||||
if (shared_network->ipv6_pools[i] == NULL) {
|
if (pond->ipv6_pools[i] == NULL) {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shared_network->last_ipv6_pool = i;
|
pond->last_ipv6_pool = i;
|
||||||
|
|
||||||
log_debug("Picking pool address %s",
|
log_debug("Picking pool address %s",
|
||||||
inet_ntop(AF_INET6, &((*addr)->addr),
|
inet_ntop(AF_INET6, &((*addr)->addr),
|
||||||
tmp_buf, sizeof(tmp_buf)));
|
tmp_buf, sizeof(tmp_buf)));
|
||||||
return ISC_R_SUCCESS;
|
return (ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
if (shared_network->ipv6_pools[i] == NULL) {
|
if (pond->ipv6_pools[i] == NULL) {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
} while (i != start_pool);
|
} while (i != start_pool);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we failed to pick an IPv6 address from any of the subnets.
|
* If we failed to pick an IPv6 address from any of the subnets.
|
||||||
@ -1134,54 +1165,77 @@ try_client_v6_prefix(struct iasubopt **pref,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*!
|
||||||
* Get an IPv6 prefix for the client.
|
|
||||||
*
|
*
|
||||||
* pref is the result (should be a pointer to NULL on entry)
|
* \brief Get an IPv6 prefix for the client.
|
||||||
* packet is the information about the packet from the client
|
*
|
||||||
* requested_iaprefix is a hint from the client
|
* Attempt to find a usable prefix for the client. We walk through
|
||||||
* plen is -1 or the requested prefix length
|
* the ponds checking for permit and deny then through the pools
|
||||||
* client_id is the DUID for the client
|
* seeing if they have an available prefix.
|
||||||
|
*
|
||||||
|
* \param reply = the state structure for the current work on this request
|
||||||
|
* if we create a lease we return it using reply->lease
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = we were able to find an prefix and are returning a
|
||||||
|
* pointer to the lease
|
||||||
|
* ISC_R_NORESOURCES = there don't appear to be any free addresses. This
|
||||||
|
* is probabalistic. We don't exhaustively try the
|
||||||
|
* address range, instead we hash the duid and if
|
||||||
|
* the address derived from the hash is in use we
|
||||||
|
* hash the address. After a number of failures we
|
||||||
|
* conclude the pool is basically full.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
pick_v6_prefix(struct iasubopt **pref, int plen,
|
pick_v6_prefix(struct reply_state *reply)
|
||||||
struct shared_network *shared_network,
|
|
||||||
const struct data_string *client_id)
|
|
||||||
{
|
{
|
||||||
struct ipv6_pool *p;
|
struct ipv6_pool *p = NULL;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
int i;
|
int i;
|
||||||
unsigned int attempts;
|
unsigned int attempts;
|
||||||
char tmp_buf[INET6_ADDRSTRLEN];
|
char tmp_buf[INET6_ADDRSTRLEN];
|
||||||
|
struct iasubopt **pref = &reply->lease;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No prefix pools, we're done.
|
* Do a quick walk through of the ponds and pools
|
||||||
|
* to see if we have any prefix pools
|
||||||
*/
|
*/
|
||||||
if (shared_network->ipv6_pools == NULL) {
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (pond->ipv6_pools == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
|
if (p->pool_type == D6O_IA_PD)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here and p is NULL we have no useful pools */
|
||||||
|
if (p == NULL) {
|
||||||
log_debug("Unable to pick client prefix: "
|
log_debug("Unable to pick client prefix: "
|
||||||
"no IPv6 pools on this shared network");
|
"no IPv6 pools on this shared network");
|
||||||
return ISC_R_NORESOURCES;
|
return ISC_R_NORESOURCES;
|
||||||
}
|
}
|
||||||
for (i = 0;; i++) {
|
|
||||||
p = shared_network->ipv6_pools[i];
|
|
||||||
if (p == NULL) {
|
|
||||||
log_debug("Unable to pick client prefix: "
|
|
||||||
"no IPv6 prefix pools "
|
|
||||||
"on this shared network");
|
|
||||||
return ISC_R_NORESOURCES;
|
|
||||||
}
|
|
||||||
if (p->pool_type == D6O_IA_PD) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise try to get a prefix.
|
* We have at least one pool that could provide a prefix
|
||||||
|
* Now we walk through the ponds and pools again and check
|
||||||
|
* to see if the client is permitted and if an prefix is
|
||||||
|
* available
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
for (i = 0;; i++) {
|
|
||||||
p = shared_network->ipv6_pools[i];
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
if (p == NULL) {
|
if (((pond->prohibit_list != NULL) &&
|
||||||
break;
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
}
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
if (p->pool_type != D6O_IA_PD) {
|
if (p->pool_type != D6O_IA_PD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1189,17 +1243,19 @@ pick_v6_prefix(struct iasubopt **pref, int plen,
|
|||||||
/*
|
/*
|
||||||
* Try only pools with the requested prefix length if any.
|
* Try only pools with the requested prefix length if any.
|
||||||
*/
|
*/
|
||||||
if ((plen >= 0) && (p->units != plen)) {
|
if ((reply->preflen >= 0) && (p->units != reply->preflen)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_prefix6(p, pref, &attempts, client_id,
|
if (create_prefix6(p, pref, &attempts, &reply->ia->iaid_duid,
|
||||||
cur_time + 120) == ISC_R_SUCCESS) {
|
cur_time + 120) == ISC_R_SUCCESS) {
|
||||||
log_debug("Picking pool prefix %s/%u",
|
log_debug("Picking pool prefix %s/%u",
|
||||||
inet_ntop(AF_INET6, &((*pref)->addr),
|
inet_ntop(AF_INET6, &((*pref)->addr),
|
||||||
tmp_buf, sizeof(tmp_buf)),
|
tmp_buf, sizeof(tmp_buf)),
|
||||||
(unsigned) (*pref)->plen);
|
(unsigned) (*pref)->plen);
|
||||||
return ISC_R_SUCCESS;
|
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,6 +1314,7 @@ lease_to_client(struct data_string *reply_ret,
|
|||||||
#if defined (RFC3315_PRE_ERRATA_2010_08)
|
#if defined (RFC3315_PRE_ERRATA_2010_08)
|
||||||
isc_boolean_t no_resources_avail = ISC_FALSE;
|
isc_boolean_t no_resources_avail = ISC_FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
int i;
|
||||||
|
|
||||||
memset(&packet_oro, 0, sizeof(packet_oro));
|
memset(&packet_oro, 0, sizeof(packet_oro));
|
||||||
|
|
||||||
@ -1298,20 +1355,26 @@ lease_to_client(struct data_string *reply_ret,
|
|||||||
* valid for the shared network the client is on.
|
* valid for the shared network the client is on.
|
||||||
*/
|
*/
|
||||||
if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
|
if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
|
||||||
MDL))
|
MDL)) {
|
||||||
|
packet->known = 1;
|
||||||
seek_shared_host(&reply.host, reply.shared);
|
seek_shared_host(&reply.host, reply.shared);
|
||||||
|
}
|
||||||
|
|
||||||
if ((reply.host == NULL) &&
|
if ((reply.host == NULL) &&
|
||||||
find_hosts_by_option(&reply.host, packet, packet->options, MDL))
|
find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
|
||||||
|
packet->known = 1;
|
||||||
seek_shared_host(&reply.host, reply.shared);
|
seek_shared_host(&reply.host, reply.shared);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for 'hardware' matches last, as some of the synthesis methods
|
* Check for 'hardware' matches last, as some of the synthesis methods
|
||||||
* are not considered to be as reliable.
|
* are not considered to be as reliable.
|
||||||
*/
|
*/
|
||||||
if ((reply.host == NULL) &&
|
if ((reply.host == NULL) &&
|
||||||
find_hosts_by_duid_chaddr(&reply.host, client_id))
|
find_hosts_by_duid_chaddr(&reply.host, client_id)) {
|
||||||
|
packet->known = 1;
|
||||||
seek_shared_host(&reply.host, reply.shared);
|
seek_shared_host(&reply.host, reply.shared);
|
||||||
|
}
|
||||||
|
|
||||||
/* Process the client supplied IA's onto the reply buffer. */
|
/* Process the client supplied IA's onto the reply buffer. */
|
||||||
reply.ia_count = 0;
|
reply.ia_count = 0;
|
||||||
@ -1412,6 +1475,17 @@ lease_to_client(struct data_string *reply_ret,
|
|||||||
reply.shared->group, root_group,
|
reply.shared->group, root_group,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
/* Execute statements from class scopes. */
|
||||||
|
for (i = reply.packet->class_count; i > 0; i--) {
|
||||||
|
execute_statements_in_scope(NULL, reply.packet,
|
||||||
|
NULL, NULL,
|
||||||
|
reply.packet->options,
|
||||||
|
reply.opt_state,
|
||||||
|
&global_scope,
|
||||||
|
reply.packet->classes[i - 1]->group,
|
||||||
|
reply.shared->group, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Bring in any configuration from a host record. */
|
/* Bring in any configuration from a host record. */
|
||||||
if (reply.host != NULL)
|
if (reply.host != NULL)
|
||||||
execute_statements_in_scope(NULL, reply.packet,
|
execute_statements_in_scope(NULL, reply.packet,
|
||||||
@ -2183,7 +2257,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
|
|||||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
|
||||||
scope = &reply->lease->scope;
|
scope = &reply->lease->scope;
|
||||||
group = reply->lease->ipv6_pool->subnet->group;
|
group = reply->lease->ipv6_pool->ipv6_pond->group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2254,6 +2328,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
|
|||||||
static isc_boolean_t
|
static isc_boolean_t
|
||||||
address_is_owned(struct reply_state *reply, struct iaddr *addr) {
|
address_is_owned(struct reply_state *reply, struct iaddr *addr) {
|
||||||
int i;
|
int i;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This faults out addresses that don't match fixed addresses.
|
* This faults out addresses that don't match fixed addresses.
|
||||||
@ -2280,7 +2355,16 @@ address_is_owned(struct reply_state *reply, struct iaddr *addr) {
|
|||||||
if (lease6_usable(tmp) == ISC_FALSE) {
|
if (lease6_usable(tmp) == ISC_FALSE) {
|
||||||
return (ISC_FALSE);
|
return (ISC_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pond = tmp->ipv6_pool->ipv6_pond;
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
return (ISC_FALSE);
|
||||||
|
|
||||||
iasubopt_reference(&reply->lease, tmp, MDL);
|
iasubopt_reference(&reply->lease, tmp, MDL);
|
||||||
|
|
||||||
return (ISC_TRUE);
|
return (ISC_TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2416,7 +2500,7 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
|
|||||||
goto bad_temp;
|
goto bad_temp;
|
||||||
status = reply_process_is_addressed(reply,
|
status = reply_process_is_addressed(reply,
|
||||||
&reply->lease->scope,
|
&reply->lease->scope,
|
||||||
reply->shared->group);
|
reply->lease->ipv6_pool->ipv6_pond->group);
|
||||||
if (status != ISC_R_SUCCESS)
|
if (status != ISC_R_SUCCESS)
|
||||||
goto bad_temp;
|
goto bad_temp;
|
||||||
status = reply_process_send_addr(reply, &tmp_addr);
|
status = reply_process_send_addr(reply, &tmp_addr);
|
||||||
@ -2621,7 +2705,8 @@ static isc_boolean_t
|
|||||||
temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
|
temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
|
||||||
struct in6_addr tmp_addr;
|
struct in6_addr tmp_addr;
|
||||||
struct subnet *subnet;
|
struct subnet *subnet;
|
||||||
struct ipv6_pool *pool;
|
struct ipv6_pool *pool = NULL;
|
||||||
|
struct ipv6_pond *pond = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
|
memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
|
||||||
@ -2656,14 +2741,25 @@ temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
|
|||||||
/*
|
/*
|
||||||
* Verify that this address is in a temporary pool and try to get it.
|
* Verify that this address is in a temporary pool and try to get it.
|
||||||
*/
|
*/
|
||||||
if (reply->shared->ipv6_pools == NULL)
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
return ISC_FALSE;
|
if (((pond->prohibit_list != NULL) &&
|
||||||
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
|
||||||
if (pool->pool_type != D6O_IA_TA)
|
if (pool->pool_type != D6O_IA_TA)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ipv6_in_pool(&tmp_addr, pool))
|
if (ipv6_in_pool(&tmp_addr, pool))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pool != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (pool == NULL)
|
if (pool == NULL)
|
||||||
return ISC_FALSE;
|
return ISC_FALSE;
|
||||||
if (lease6_exists(pool, &tmp_addr))
|
if (lease6_exists(pool, &tmp_addr))
|
||||||
@ -2684,29 +2780,51 @@ temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
|
|||||||
*/
|
*/
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
find_client_temporaries(struct reply_state *reply) {
|
find_client_temporaries(struct reply_state *reply) {
|
||||||
struct shared_network *shared;
|
|
||||||
int i;
|
int i;
|
||||||
struct ipv6_pool *p;
|
struct ipv6_pool *p;
|
||||||
isc_result_t status;
|
struct ipv6_pond *pond;
|
||||||
|
isc_result_t status = ISC_R_NORESOURCES;;
|
||||||
unsigned int attempts;
|
unsigned int attempts;
|
||||||
struct iaddr send_addr;
|
struct iaddr send_addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No pools, we're done.
|
* Do a quick walk through of the ponds and pools
|
||||||
|
* to see if we have any prefix pools
|
||||||
*/
|
*/
|
||||||
shared = reply->shared;
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
if (shared->ipv6_pools == NULL) {
|
if (pond->ipv6_pools == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
|
if (p->pool_type == D6O_IA_TA)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here and p is NULL we have no useful pools */
|
||||||
|
if (p == NULL) {
|
||||||
log_debug("Unable to get client addresses: "
|
log_debug("Unable to get client addresses: "
|
||||||
"no IPv6 pools on this shared network");
|
"no IPv6 pools on this shared network");
|
||||||
return ISC_R_NORESOURCES;
|
return ISC_R_NORESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ISC_R_NORESOURCES;
|
/*
|
||||||
for (i = 0;; i++) {
|
* We have at least one pool that could provide an address
|
||||||
p = shared->ipv6_pools[i];
|
* Now we walk through the ponds and pools again and check
|
||||||
if (p == NULL) {
|
* to see if the client is permitted and if an address is
|
||||||
break;
|
* available
|
||||||
}
|
*/
|
||||||
|
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
if (p->pool_type != D6O_IA_TA) {
|
if (p->pool_type != D6O_IA_TA) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2723,7 +2841,7 @@ find_client_temporaries(struct reply_state *reply) {
|
|||||||
|
|
||||||
status = reply_process_is_addressed(reply,
|
status = reply_process_is_addressed(reply,
|
||||||
&reply->lease->scope,
|
&reply->lease->scope,
|
||||||
reply->lease->ipv6_pool->subnet->group);
|
pond->group);
|
||||||
if (status != ISC_R_SUCCESS) {
|
if (status != ISC_R_SUCCESS) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -2739,6 +2857,7 @@ find_client_temporaries(struct reply_state *reply) {
|
|||||||
*/
|
*/
|
||||||
iasubopt_dereference(&reply->lease, MDL);
|
iasubopt_dereference(&reply->lease, MDL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (reply->lease != NULL) {
|
if (reply->lease != NULL) {
|
||||||
@ -2754,7 +2873,8 @@ find_client_temporaries(struct reply_state *reply) {
|
|||||||
static isc_result_t
|
static isc_result_t
|
||||||
reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
|
reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
|
||||||
isc_result_t status = ISC_R_ADDRNOTAVAIL;
|
isc_result_t status = ISC_R_ADDRNOTAVAIL;
|
||||||
struct ipv6_pool *pool;
|
struct ipv6_pool *pool = NULL;
|
||||||
|
struct ipv6_pond *pond = NULL;
|
||||||
int i;
|
int i;
|
||||||
struct data_string data_addr;
|
struct data_string data_addr;
|
||||||
|
|
||||||
@ -2762,22 +2882,65 @@ reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
|
|||||||
(addr == NULL) || (reply->lease != NULL))
|
(addr == NULL) || (reply->lease != NULL))
|
||||||
return (DHCP_R_INVALIDARG);
|
return (DHCP_R_INVALIDARG);
|
||||||
|
|
||||||
if (reply->shared->ipv6_pools == NULL)
|
/*
|
||||||
|
* Do a quick walk through of the ponds and pools
|
||||||
|
* to see if we have any NA address pools
|
||||||
|
*/
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (pond->ipv6_pools == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
pool = pond->ipv6_pools[i];
|
||||||
|
if ((pool == NULL) ||
|
||||||
|
(pool->pool_type == D6O_IA_NA))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pool != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here and p is NULL we have no useful pools */
|
||||||
|
if (pool == NULL) {
|
||||||
return (ISC_R_ADDRNOTAVAIL);
|
return (ISC_R_ADDRNOTAVAIL);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&data_addr, 0, sizeof(data_addr));
|
memset(&data_addr, 0, sizeof(data_addr));
|
||||||
data_addr.len = addr->len;
|
data_addr.len = addr->len;
|
||||||
data_addr.data = addr->iabuf;
|
data_addr.data = addr->iabuf;
|
||||||
|
|
||||||
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
|
/*
|
||||||
|
* We have at least one pool that could provide an address
|
||||||
|
* Now we walk through the ponds and pools again and check
|
||||||
|
* to see if the client is permitted and if an address is
|
||||||
|
* available
|
||||||
|
*
|
||||||
|
* Within a given pond we start looking at the last pool we
|
||||||
|
* allocated from, unless it had a collision trying to allocate
|
||||||
|
* an address. This will tend to move us into less-filled pools.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
|
||||||
if (pool->pool_type != D6O_IA_NA)
|
if (pool->pool_type != D6O_IA_NA)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
status = try_client_v6_address(&reply->lease, pool,
|
status = try_client_v6_address(&reply->lease, pool,
|
||||||
&data_addr);
|
&data_addr);
|
||||||
if (status == ISC_R_SUCCESS)
|
if (status == ISC_R_SUCCESS)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status == ISC_R_SUCCESS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Note that this is just pedantry. There is no allocation to free. */
|
/* Note that this is just pedantry. There is no allocation to free. */
|
||||||
data_string_forget(&data_addr, MDL);
|
data_string_forget(&data_addr, MDL);
|
||||||
/* Return just the most recent status... */
|
/* Return just the most recent status... */
|
||||||
@ -2812,27 +2975,36 @@ find_client_address(struct reply_state *reply) {
|
|||||||
if (reply->old_ia != NULL) {
|
if (reply->old_ia != NULL) {
|
||||||
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
|
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
|
||||||
struct shared_network *candidate_shared;
|
struct shared_network *candidate_shared;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
|
|
||||||
lease = reply->old_ia->iasubopt[i];
|
lease = reply->old_ia->iasubopt[i];
|
||||||
candidate_shared = lease->ipv6_pool->shared_network;
|
candidate_shared = lease->ipv6_pool->shared_network;
|
||||||
|
pond = lease->ipv6_pool->ipv6_pond;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for the best lease on the client's shared
|
* Look for the best lease on the client's shared
|
||||||
* network.
|
* network, that is still permitted
|
||||||
*/
|
*/
|
||||||
if ((candidate_shared == reply->shared) &&
|
|
||||||
(lease6_usable(lease) == ISC_TRUE)) {
|
if ((candidate_shared != reply->shared) ||
|
||||||
|
(lease6_usable(lease) != ISC_TRUE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
best_lease = lease_compare(lease, best_lease);
|
best_lease = lease_compare(lease, best_lease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to pick a new address if we didn't find one, or if we found an
|
/* Try to pick a new address if we didn't find one, or if we found an
|
||||||
* abandoned lease.
|
* abandoned lease.
|
||||||
*/
|
*/
|
||||||
if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
|
if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
|
||||||
status = pick_v6_address(&reply->lease, reply->shared,
|
status = pick_v6_address(reply);
|
||||||
&reply->ia->iaid_duid);
|
|
||||||
} else if (best_lease != NULL) {
|
} else if (best_lease != NULL) {
|
||||||
iasubopt_reference(&reply->lease, best_lease, MDL);
|
iasubopt_reference(&reply->lease, best_lease, MDL);
|
||||||
status = ISC_R_SUCCESS;
|
status = ISC_R_SUCCESS;
|
||||||
@ -2859,7 +3031,7 @@ find_client_address(struct reply_state *reply) {
|
|||||||
* be desirable to place the group attachment directly in the pool.
|
* be desirable to place the group attachment directly in the pool.
|
||||||
*/
|
*/
|
||||||
scope = &reply->lease->scope;
|
scope = &reply->lease->scope;
|
||||||
group = reply->lease->ipv6_pool->subnet->group;
|
group = reply->lease->ipv6_pool->ipv6_pond->group;
|
||||||
|
|
||||||
send_addr.len = 16;
|
send_addr.len = 16;
|
||||||
memcpy(send_addr.iabuf, &reply->lease->addr, 16);
|
memcpy(send_addr.iabuf, &reply->lease->addr, 16);
|
||||||
@ -2886,6 +3058,7 @@ reply_process_is_addressed(struct reply_state *reply,
|
|||||||
struct option_cache *oc;
|
struct option_cache *oc;
|
||||||
struct option_state *tmp_options = NULL;
|
struct option_state *tmp_options = NULL;
|
||||||
struct on_star *on_star;
|
struct on_star *on_star;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize values we will cleanup. */
|
/* Initialize values we will cleanup. */
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
@ -2925,6 +3098,15 @@ reply_process_is_addressed(struct reply_state *reply,
|
|||||||
reply->packet->options, reply->opt_state,
|
reply->packet->options, reply->opt_state,
|
||||||
scope, group, root_group, on_star);
|
scope, group, root_group, on_star);
|
||||||
|
|
||||||
|
/* Execute statements from class scopes. */
|
||||||
|
for (i = reply->packet->class_count; i > 0; i--) {
|
||||||
|
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
|
||||||
|
reply->packet->options,
|
||||||
|
reply->opt_state, scope,
|
||||||
|
reply->packet->classes[i - 1]->group,
|
||||||
|
group, on_star);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is a host record, over-ride with values configured there,
|
* If there is a host record, over-ride with values configured there,
|
||||||
* without re-evaluating configuration from the previously executed
|
* without re-evaluating configuration from the previously executed
|
||||||
@ -3043,6 +3225,15 @@ reply_process_is_addressed(struct reply_state *reply,
|
|||||||
reply->packet->options, reply->reply_ia,
|
reply->packet->options, reply->reply_ia,
|
||||||
scope, group, root_group, NULL);
|
scope, group, root_group, NULL);
|
||||||
|
|
||||||
|
/* Execute statements from class scopes. */
|
||||||
|
for (i = reply->packet->class_count; i > 0; i--) {
|
||||||
|
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
|
||||||
|
reply->packet->options,
|
||||||
|
reply->reply_ia, scope,
|
||||||
|
reply->packet->classes[i - 1]->group,
|
||||||
|
group, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And bring in host record configuration, if any, but not to overlap
|
* And bring in host record configuration, if any, but not to overlap
|
||||||
* the previous group or its common enclosers.
|
* the previous group or its common enclosers.
|
||||||
@ -3540,6 +3731,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
|
|||||||
struct option_cache *oc;
|
struct option_cache *oc;
|
||||||
struct data_string iapref, data;
|
struct data_string iapref, data;
|
||||||
isc_result_t status = ISC_R_SUCCESS;
|
isc_result_t status = ISC_R_SUCCESS;
|
||||||
|
struct group *group;
|
||||||
|
|
||||||
/* Initializes values that will be cleaned up. */
|
/* Initializes values that will be cleaned up. */
|
||||||
memset(&iapref, 0, sizeof(iapref));
|
memset(&iapref, 0, sizeof(iapref));
|
||||||
@ -3681,11 +3873,19 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
|
|||||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
|
||||||
scope = &global_scope;
|
scope = &global_scope;
|
||||||
|
|
||||||
|
/* Find the static prefixe's subnet. */
|
||||||
|
if (find_grouped_subnet(&reply->subnet, reply->shared,
|
||||||
|
tmp_pref.lo_addr, MDL) == 0)
|
||||||
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
group = reply->subnet->group;
|
||||||
|
subnet_dereference(&reply->subnet, MDL);
|
||||||
} else {
|
} else {
|
||||||
if (reply->lease == NULL)
|
if (reply->lease == NULL)
|
||||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
|
||||||
scope = &reply->lease->scope;
|
scope = &reply->lease->scope;
|
||||||
|
group = reply->lease->ipv6_pool->ipv6_pond->group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3729,7 +3929,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = reply_process_is_prefixed(reply, scope, reply->shared->group);
|
status = reply_process_is_prefixed(reply, scope, group);
|
||||||
if (status != ISC_R_SUCCESS)
|
if (status != ISC_R_SUCCESS)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -3757,6 +3957,7 @@ static isc_boolean_t
|
|||||||
prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
|
prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
|
||||||
struct iaddrcidrnetlist *l;
|
struct iaddrcidrnetlist *l;
|
||||||
int i;
|
int i;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This faults out prefixes that don't match fixed prefixes.
|
* This faults out prefixes that don't match fixed prefixes.
|
||||||
@ -3785,6 +3986,14 @@ prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
|
|||||||
if (lease6_usable(tmp) == ISC_FALSE) {
|
if (lease6_usable(tmp) == ISC_FALSE) {
|
||||||
return (ISC_FALSE);
|
return (ISC_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pond = tmp->ipv6_pool->ipv6_pond;
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
return (ISC_FALSE);
|
||||||
|
|
||||||
iasubopt_reference(&reply->lease, tmp, MDL);
|
iasubopt_reference(&reply->lease, tmp, MDL);
|
||||||
return (ISC_TRUE);
|
return (ISC_TRUE);
|
||||||
}
|
}
|
||||||
@ -3801,7 +4010,8 @@ static isc_result_t
|
|||||||
reply_process_try_prefix(struct reply_state *reply,
|
reply_process_try_prefix(struct reply_state *reply,
|
||||||
struct iaddrcidrnet *pref) {
|
struct iaddrcidrnet *pref) {
|
||||||
isc_result_t status = ISC_R_ADDRNOTAVAIL;
|
isc_result_t status = ISC_R_ADDRNOTAVAIL;
|
||||||
struct ipv6_pool *pool;
|
struct ipv6_pool *pool = NULL;
|
||||||
|
struct ipv6_pond *pond = NULL;
|
||||||
int i;
|
int i;
|
||||||
struct data_string data_pref;
|
struct data_string data_pref;
|
||||||
|
|
||||||
@ -3809,8 +4019,26 @@ reply_process_try_prefix(struct reply_state *reply,
|
|||||||
(pref == NULL) || (reply->lease != NULL))
|
(pref == NULL) || (reply->lease != NULL))
|
||||||
return (DHCP_R_INVALIDARG);
|
return (DHCP_R_INVALIDARG);
|
||||||
|
|
||||||
if (reply->shared->ipv6_pools == NULL)
|
/*
|
||||||
|
* Do a quick walk through of the ponds and pools
|
||||||
|
* to see if we have any prefix pools
|
||||||
|
*/
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (pond->ipv6_pools == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
|
if (pool->pool_type == D6O_IA_PD)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pool != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we get here and p is NULL we have no useful pools */
|
||||||
|
if (pool == NULL) {
|
||||||
return (ISC_R_ADDRNOTAVAIL);
|
return (ISC_R_ADDRNOTAVAIL);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&data_pref, 0, sizeof(data_pref));
|
memset(&data_pref, 0, sizeof(data_pref));
|
||||||
data_pref.len = 17;
|
data_pref.len = 17;
|
||||||
@ -3822,9 +4050,26 @@ reply_process_try_prefix(struct reply_state *reply,
|
|||||||
data_pref.buffer->data[0] = (u_int8_t) pref->bits;
|
data_pref.buffer->data[0] = (u_int8_t) pref->bits;
|
||||||
memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
|
memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
|
||||||
|
|
||||||
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
|
/*
|
||||||
if (pool->pool_type != D6O_IA_PD)
|
* We have at least one pool that could provide a prefix
|
||||||
|
* Now we walk through the ponds and pools again and check
|
||||||
|
* to see if the client is permitted and if an prefix is
|
||||||
|
* available
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
|
||||||
|
if (pool->pool_type != D6O_IA_PD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
status = try_client_v6_prefix(&reply->lease, pool,
|
status = try_client_v6_prefix(&reply->lease, pool,
|
||||||
&data_pref);
|
&data_pref);
|
||||||
/* If we found it in this pool (either in use or available),
|
/* If we found it in this pool (either in use or available),
|
||||||
@ -3832,6 +4077,9 @@ reply_process_try_prefix(struct reply_state *reply,
|
|||||||
if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
|
if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
data_string_forget(&data_pref, MDL);
|
data_string_forget(&data_pref, MDL);
|
||||||
/* Return just the most recent status... */
|
/* Return just the most recent status... */
|
||||||
@ -3849,6 +4097,7 @@ find_client_prefix(struct reply_state *reply) {
|
|||||||
struct iasubopt *prefix, *best_prefix = NULL;
|
struct iasubopt *prefix, *best_prefix = NULL;
|
||||||
struct binding_scope **scope;
|
struct binding_scope **scope;
|
||||||
int i;
|
int i;
|
||||||
|
struct group *group;
|
||||||
|
|
||||||
if (reply->static_prefixes > 0) {
|
if (reply->static_prefixes > 0) {
|
||||||
struct iaddrcidrnetlist *l;
|
struct iaddrcidrnetlist *l;
|
||||||
@ -3870,36 +4119,56 @@ find_client_prefix(struct reply_state *reply) {
|
|||||||
memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
|
memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
|
||||||
|
|
||||||
scope = &global_scope;
|
scope = &global_scope;
|
||||||
|
|
||||||
|
/* Find the static prefixe's subnet. */
|
||||||
|
if (find_grouped_subnet(&reply->subnet, reply->shared,
|
||||||
|
send_pref.lo_addr, MDL) == 0)
|
||||||
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
group = reply->subnet->group;
|
||||||
|
subnet_dereference(&reply->subnet, MDL);
|
||||||
|
|
||||||
goto send_pref;
|
goto send_pref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply->old_ia != NULL) {
|
if (reply->old_ia != NULL) {
|
||||||
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
|
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
|
||||||
struct shared_network *candidate_shared;
|
struct shared_network *candidate_shared;
|
||||||
|
struct ipv6_pond *pond;
|
||||||
|
|
||||||
prefix = reply->old_ia->iasubopt[i];
|
prefix = reply->old_ia->iasubopt[i];
|
||||||
candidate_shared = prefix->ipv6_pool->shared_network;
|
candidate_shared = prefix->ipv6_pool->shared_network;
|
||||||
|
pond = prefix->ipv6_pool->ipv6_pond;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Consider this prefix if it is in a global pool or
|
* Consider this prefix if it is in a global pool or
|
||||||
* if it is scoped in a pool under the client's shared
|
* if it is scoped in a pool under the client's shared
|
||||||
* network.
|
* network.
|
||||||
*/
|
*/
|
||||||
if (((candidate_shared == NULL) ||
|
if (((candidate_shared != NULL) &&
|
||||||
(candidate_shared == reply->shared)) &&
|
(candidate_shared != reply->shared)) ||
|
||||||
(lease6_usable(prefix) == ISC_TRUE)) {
|
(lease6_usable(prefix) != ISC_TRUE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And check if the prefix is still permitted
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((pond->prohibit_list != NULL) &&
|
||||||
|
(permitted(reply->packet, pond->prohibit_list))) ||
|
||||||
|
((pond->permit_list != NULL) &&
|
||||||
|
(!permitted(reply->packet, pond->permit_list))))
|
||||||
|
continue;
|
||||||
|
|
||||||
best_prefix = prefix_compare(reply, prefix,
|
best_prefix = prefix_compare(reply, prefix,
|
||||||
best_prefix);
|
best_prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to pick a new prefix if we didn't find one, or if we found an
|
/* Try to pick a new prefix if we didn't find one, or if we found an
|
||||||
* abandoned prefix.
|
* abandoned prefix.
|
||||||
*/
|
*/
|
||||||
if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
|
if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
|
||||||
status = pick_v6_prefix(&reply->lease, reply->preflen,
|
status = pick_v6_prefix(reply);
|
||||||
reply->shared, &reply->client_id);
|
|
||||||
} else if (best_prefix != NULL) {
|
} else if (best_prefix != NULL) {
|
||||||
iasubopt_reference(&reply->lease, best_prefix, MDL);
|
iasubopt_reference(&reply->lease, best_prefix, MDL);
|
||||||
status = ISC_R_SUCCESS;
|
status = ISC_R_SUCCESS;
|
||||||
@ -3922,13 +4191,14 @@ find_client_prefix(struct reply_state *reply) {
|
|||||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||||
|
|
||||||
scope = &reply->lease->scope;
|
scope = &reply->lease->scope;
|
||||||
|
group = reply->lease->ipv6_pool->ipv6_pond->group;
|
||||||
|
|
||||||
send_pref.lo_addr.len = 16;
|
send_pref.lo_addr.len = 16;
|
||||||
memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
|
memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
|
||||||
send_pref.bits = (int) reply->lease->plen;
|
send_pref.bits = (int) reply->lease->plen;
|
||||||
|
|
||||||
send_pref:
|
send_pref:
|
||||||
status = reply_process_is_prefixed(reply, scope, reply->shared->group);
|
status = reply_process_is_prefixed(reply, scope, group);
|
||||||
if (status != ISC_R_SUCCESS)
|
if (status != ISC_R_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@ -3949,6 +4219,7 @@ reply_process_is_prefixed(struct reply_state *reply,
|
|||||||
struct option_cache *oc;
|
struct option_cache *oc;
|
||||||
struct option_state *tmp_options = NULL;
|
struct option_state *tmp_options = NULL;
|
||||||
struct on_star *on_star;
|
struct on_star *on_star;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Initialize values we will cleanup. */
|
/* Initialize values we will cleanup. */
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
@ -3988,6 +4259,15 @@ reply_process_is_prefixed(struct reply_state *reply,
|
|||||||
reply->packet->options, reply->opt_state,
|
reply->packet->options, reply->opt_state,
|
||||||
scope, group, root_group, on_star);
|
scope, group, root_group, on_star);
|
||||||
|
|
||||||
|
/* Execute statements from class scopes. */
|
||||||
|
for (i = reply->packet->class_count; i > 0; i--) {
|
||||||
|
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
|
||||||
|
reply->packet->options,
|
||||||
|
reply->opt_state, scope,
|
||||||
|
reply->packet->classes[i - 1]->group,
|
||||||
|
group, on_star);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is a host record, over-ride with values configured there,
|
* If there is a host record, over-ride with values configured there,
|
||||||
* without re-evaluating configuration from the previously executed
|
* without re-evaluating configuration from the previously executed
|
||||||
@ -4091,6 +4371,15 @@ reply_process_is_prefixed(struct reply_state *reply,
|
|||||||
reply->packet->options, reply->reply_ia,
|
reply->packet->options, reply->reply_ia,
|
||||||
scope, group, root_group, NULL);
|
scope, group, root_group, NULL);
|
||||||
|
|
||||||
|
/* Execute statements from class scopes. */
|
||||||
|
for (i = reply->packet->class_count; i > 0; i--) {
|
||||||
|
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
|
||||||
|
reply->packet->options,
|
||||||
|
reply->reply_ia, scope,
|
||||||
|
reply->packet->classes[i - 1]->group,
|
||||||
|
group, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And bring in host record configuration, if any, but not to overlap
|
* And bring in host record configuration, if any, but not to overlap
|
||||||
* the previous group or its common enclosers.
|
* the previous group or its common enclosers.
|
||||||
@ -5888,6 +6177,10 @@ dhcpv6_discard(struct packet *packet) {
|
|||||||
static void
|
static void
|
||||||
build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
|
build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
|
||||||
memset(reply, 0, sizeof(*reply));
|
memset(reply, 0, sizeof(*reply));
|
||||||
|
|
||||||
|
/* Classify the client */
|
||||||
|
classify_client(packet);
|
||||||
|
|
||||||
switch (packet->dhcpv6_msg_type) {
|
switch (packet->dhcpv6_msg_type) {
|
||||||
case DHCPV6_SOLICIT:
|
case DHCPV6_SOLICIT:
|
||||||
dhcpv6_solicit(reply, packet);
|
dhcpv6_solicit(reply, packet);
|
||||||
|
288
server/mdb6.c
288
server/mdb6.c
@ -25,7 +25,34 @@
|
|||||||
*
|
*
|
||||||
* A brief description of the IPv6 structures as reverse engineered.
|
* A brief description of the IPv6 structures as reverse engineered.
|
||||||
*
|
*
|
||||||
* There are three major data strucutes involved in the database:
|
* There are four major data structures in the lease configuraion.
|
||||||
|
*
|
||||||
|
* - shared_network - The shared network is the outer enclosing scope for a
|
||||||
|
* network region that shares a broadcast domain. It is
|
||||||
|
* composed of one or more subnets all of which are valid
|
||||||
|
* in the given region. The share network may be
|
||||||
|
* explicitly defined or implicitly created if there is
|
||||||
|
* only a subnet statement. This structrure is shared
|
||||||
|
* with v4. Each shared network statment or naked subnet
|
||||||
|
* will map to one of these structures
|
||||||
|
*
|
||||||
|
* - subnet - The subnet structure mostly specifies the address range
|
||||||
|
* that could be valid in a given region. This structute
|
||||||
|
* doesn't include the addresses that the server can delegate
|
||||||
|
* those are in the ipv6_pool. This structure is also shared
|
||||||
|
* with v4. Each subnet statement will map to one of these
|
||||||
|
* structures.
|
||||||
|
*
|
||||||
|
* - ipv6_pond - The pond structure is a grouping of the address and prefix
|
||||||
|
* information via the pointers to the ipv6_pool and the
|
||||||
|
* allowability of this pool for given clinets via the permit
|
||||||
|
* lists and the valid TIMEs. This is equivilent to the v4
|
||||||
|
* pool structure and would have been named ip6_pool except
|
||||||
|
* that the name was already in use. Generally each pool6
|
||||||
|
* statement will map to one of these structures. In addition
|
||||||
|
* there may be one or for each group of naked range6 and
|
||||||
|
* prefix6 statements within a shared network that share
|
||||||
|
* the same group of statements.
|
||||||
*
|
*
|
||||||
* - ipv6_pool - this contains information about a pool of addresses or prefixes
|
* - ipv6_pool - this contains information about a pool of addresses or prefixes
|
||||||
* that the server is using. This includes a hash table that
|
* that the server is using. This includes a hash table that
|
||||||
@ -33,6 +60,65 @@
|
|||||||
* active items and one for non-active items. The heap tables
|
* active items and one for non-active items. The heap tables
|
||||||
* are used to determine the next items to be modified due to
|
* are used to determine the next items to be modified due to
|
||||||
* timing events (expire mostly).
|
* timing events (expire mostly).
|
||||||
|
*
|
||||||
|
* The linkages then look like this:
|
||||||
|
* \verbatim
|
||||||
|
*+--------------+ +-------------+
|
||||||
|
*|Shared Network| | ipv6_pond |
|
||||||
|
*| group | | group |
|
||||||
|
*| | | permit info |
|
||||||
|
*| | | next ---->
|
||||||
|
*| ponds ---->| |
|
||||||
|
*| |<---- shared |
|
||||||
|
*| Subnets | | pools |
|
||||||
|
*+-----|--------+ +------|------+
|
||||||
|
* | ^ | ^
|
||||||
|
* | | v |
|
||||||
|
* | | +-----------|-+
|
||||||
|
* | | | ipv6_pool | |
|
||||||
|
* | | | type | |
|
||||||
|
* | | | ipv6_pond |
|
||||||
|
* | | | |
|
||||||
|
* | | | next ---->
|
||||||
|
* | | | |
|
||||||
|
* | | | subnet |
|
||||||
|
* | | +-----|-------+
|
||||||
|
* | | |
|
||||||
|
* | | v
|
||||||
|
* | | +-------------+
|
||||||
|
* | | | subnet |
|
||||||
|
* | +---------- shared |
|
||||||
|
* +----------->| |
|
||||||
|
* | group |
|
||||||
|
* +-------------+
|
||||||
|
*
|
||||||
|
* The shared network contains a list of all the subnets that are on a broadcast
|
||||||
|
* doamin. These can be used to determine if an address makes sense in a given
|
||||||
|
* domain, but the subnets do not contain the addresses the server can delegate.
|
||||||
|
* Those are stored in the ponds and pools.
|
||||||
|
*
|
||||||
|
* In the simple case to find an acceptable address the server would first find
|
||||||
|
* the shared network the client is on based on either the interface used to
|
||||||
|
* receive the request or the relay agent's information. From the shared
|
||||||
|
* network the server will walk through it's list of ponds. For each pond it
|
||||||
|
* will evaluate the permit information against the (already done) classification.
|
||||||
|
* If it finds an acceptable pond it will then walk through the pools for that
|
||||||
|
* pond. The server first checks the type of the pool (NA, TA and PD) agaisnt the
|
||||||
|
* request and if they match it attemps to find an address within that pool. On
|
||||||
|
* success the address is used, on failure the server steps to the next pool and
|
||||||
|
* if necessary to the next pond.
|
||||||
|
*
|
||||||
|
* When the server is successful in finding an address it will execute any
|
||||||
|
* statements assocaited with the pond, then the subnet, then the shared
|
||||||
|
* network the group field is for in the above picture).
|
||||||
|
*
|
||||||
|
* In configurations that don't include either a shared network or a pool6
|
||||||
|
* statement (or both) the missing pieces are created.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* There are three major data structuress involved in the lease database:
|
||||||
|
*
|
||||||
|
* - ipv6_pool - see above
|
||||||
* - ia_xx - this contains information about a single IA from a request
|
* - ia_xx - this contains information about a single IA from a request
|
||||||
* normally it will contain one pointer to a lease for the client
|
* normally it will contain one pointer to a lease for the client
|
||||||
* but it may contain more in some circumstances. There are 3
|
* but it may contain more in some circumstances. There are 3
|
||||||
@ -523,11 +609,27 @@ lease_index_changed(void *iasubopt, unsigned int new_heap_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*!
|
||||||
* Create a new IPv6 lease pool structure.
|
|
||||||
*
|
*
|
||||||
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
|
* \brief Create a new IPv6 lease pool structure
|
||||||
* initialized to NULL
|
*
|
||||||
|
* Allocate space for a new ipv6_pool structure and return a reference
|
||||||
|
* to it, includes setting the reference count to 1.
|
||||||
|
*
|
||||||
|
* \param pool = space for returning a referenced pointer to the pool.
|
||||||
|
* This must point to a space that has been initialzied
|
||||||
|
* to NULL by the caller.
|
||||||
|
* \param[in] type = The type of the pool NA, TA or PD
|
||||||
|
* \param[in] start_addr = The first address in the range for the pool
|
||||||
|
* \param[in] bits = The contiguous bits of the pool
|
||||||
|
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pool was successfully created, pool points to it.
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
|
||||||
|
* modified
|
||||||
|
* ISC_R_NOMEMORY = The system wasn't able to allocate memory, pool has
|
||||||
|
* not been modified.
|
||||||
*/
|
*/
|
||||||
isc_result_t
|
isc_result_t
|
||||||
ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
|
ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
|
||||||
@ -576,11 +678,24 @@ ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
|
|||||||
return ISC_R_SUCCESS;
|
return ISC_R_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*!
|
||||||
* Reference an IPv6 pool structure.
|
|
||||||
*
|
*
|
||||||
* - pool must be a pointer to a (struct pool *) pointer previously
|
* \brief reference an IPv6 pool structure.
|
||||||
* initialized to NULL
|
*
|
||||||
|
* This function genreates a reference to an ipv6_pool structure
|
||||||
|
* and increments the reference count on the structure.
|
||||||
|
*
|
||||||
|
* \param[out] pool = space for returning a referenced pointer to the pool.
|
||||||
|
* This must point to a space that has been initialzied
|
||||||
|
* to NULL by the caller.
|
||||||
|
* \param[in] src = A pointer to the pool to reference. This must not be
|
||||||
|
* NULL.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pool was successfully referenced, pool now points
|
||||||
|
* to src.
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
|
||||||
|
* modified.
|
||||||
*/
|
*/
|
||||||
isc_result_t
|
isc_result_t
|
||||||
ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
|
ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
|
||||||
@ -634,12 +749,24 @@ dereference_heap_entry(void *value, void *dummy) {
|
|||||||
iasubopt_dereference(&iasubopt, MDL);
|
iasubopt_dereference(&iasubopt, MDL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
/*
|
|
||||||
* Dereference an IPv6 pool structure.
|
|
||||||
*
|
*
|
||||||
* If it is the last reference, then the memory for the
|
* \brief de-reference an IPv6 pool structure.
|
||||||
* structure is freed.
|
*
|
||||||
|
* This function decrements the reference count in an ipv6_pool structure.
|
||||||
|
* If this was the last reference then the memory for the structure is
|
||||||
|
* freed.
|
||||||
|
*
|
||||||
|
* \param[in] pool = A pointer to the pointer to the pool that should be
|
||||||
|
* de-referenced. On success the pointer to the pool
|
||||||
|
* is cleared. It must not be NULL and must not point
|
||||||
|
* to NULL.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pool was successfully de-referenced, pool now points
|
||||||
|
* to NULL
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
|
||||||
|
* modified.
|
||||||
*/
|
*/
|
||||||
isc_result_t
|
isc_result_t
|
||||||
ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
|
ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
|
||||||
@ -804,7 +931,7 @@ static struct in6_addr resany;
|
|||||||
/*
|
/*
|
||||||
* Create a lease for the given address and client duid.
|
* Create a lease for the given address and client duid.
|
||||||
*
|
*
|
||||||
* - pool must be a pointer to a (struct pool *) pointer previously
|
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
|
||||||
* initialized to NULL
|
* initialized to NULL
|
||||||
*
|
*
|
||||||
* Right now we simply hash the DUID, and if we get a collision, we hash
|
* Right now we simply hash the DUID, and if we get a collision, we hash
|
||||||
@ -1255,6 +1382,7 @@ move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
*
|
||||||
* \brief Renew a lease in the pool.
|
* \brief Renew a lease in the pool.
|
||||||
*
|
*
|
||||||
* The hard_lifetime_end_time of the lease should be set to
|
* The hard_lifetime_end_time of the lease should be set to
|
||||||
@ -1277,8 +1405,8 @@ move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
|
|||||||
* If the lease is moving to active we call that routine
|
* If the lease is moving to active we call that routine
|
||||||
* which will move it from the inactive list to the active list.
|
* which will move it from the inactive list to the active list.
|
||||||
*
|
*
|
||||||
* \param pool a pool the lease belongs to
|
* \param pool = a pool the lease belongs to
|
||||||
* \param lease the lease to be renewed
|
* \param lease = the lease to be renewed
|
||||||
*
|
*
|
||||||
* \return result of the renew operation (ISC_R_SUCCESS if successful,
|
* \return result of the renew operation (ISC_R_SUCCESS if successful,
|
||||||
ISC_R_NOMEMORY when run out of memory)
|
ISC_R_NOMEMORY when run out of memory)
|
||||||
@ -1518,7 +1646,7 @@ build_prefix6(struct in6_addr *pref,
|
|||||||
/*
|
/*
|
||||||
* Create a lease for the given prefix and client duid.
|
* Create a lease for the given prefix and client duid.
|
||||||
*
|
*
|
||||||
* - pool must be a pointer to a (struct pool *) pointer previously
|
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
|
||||||
* initialized to NULL
|
* initialized to NULL
|
||||||
*
|
*
|
||||||
* Right now we simply hash the DUID, and if we get a collision, we hash
|
* Right now we simply hash the DUID, and if we get a collision, we hash
|
||||||
@ -2190,4 +2318,128 @@ mark_interfaces_unavailable(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Create a new IPv6 pond structure.
|
||||||
|
*
|
||||||
|
* Allocate space for a new ipv6_pond structure and return a reference
|
||||||
|
* to it, includes setting the reference count to 1.
|
||||||
|
*
|
||||||
|
* \param pond = space for returning a referenced pointer to the pond.
|
||||||
|
* This must point to a space that has been initialzied
|
||||||
|
* to NULL by the caller.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pond was successfully created, pond points to it.
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
|
||||||
|
* modified
|
||||||
|
* ISC_R_NOMEMORY = The system wasn't able to allocate memory, pond has
|
||||||
|
* not been modified.
|
||||||
|
*/
|
||||||
|
isc_result_t
|
||||||
|
ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
|
||||||
|
struct ipv6_pond *tmp;
|
||||||
|
|
||||||
|
if (pond == NULL) {
|
||||||
|
log_error("%s(%d): NULL pointer reference", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
if (*pond != NULL) {
|
||||||
|
log_error("%s(%d): non-NULL pointer", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = dmalloc(sizeof(*tmp), file, line);
|
||||||
|
if (tmp == NULL) {
|
||||||
|
return ISC_R_NOMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp->refcnt = 1;
|
||||||
|
|
||||||
|
*pond = tmp;
|
||||||
|
return ISC_R_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief reference an IPv6 pond structure.
|
||||||
|
*
|
||||||
|
* This function genreates a reference to an ipv6_pond structure
|
||||||
|
* and increments the reference count on the structure.
|
||||||
|
*
|
||||||
|
* \param[out] pond = space for returning a referenced pointer to the pond.
|
||||||
|
* This must point to a space that has been initialzied
|
||||||
|
* to NULL by the caller.
|
||||||
|
* \param[in] src = A pointer to the pond to reference. This must not be
|
||||||
|
* NULL.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pond was successfully referenced, pond now points
|
||||||
|
* to src.
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
|
||||||
|
* modified.
|
||||||
|
*/
|
||||||
|
isc_result_t
|
||||||
|
ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
|
||||||
|
const char *file, int line) {
|
||||||
|
if (pond == NULL) {
|
||||||
|
log_error("%s(%d): NULL pointer reference", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
if (*pond != NULL) {
|
||||||
|
log_error("%s(%d): non-NULL pointer", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
if (src == NULL) {
|
||||||
|
log_error("%s(%d): NULL pointer reference", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
*pond = src;
|
||||||
|
src->refcnt++;
|
||||||
|
return ISC_R_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* \brief de-reference an IPv6 pond structure.
|
||||||
|
*
|
||||||
|
* This function decrements the reference count in an ipv6_pond structure.
|
||||||
|
* If this was the last reference then the memory for the structure is
|
||||||
|
* freed.
|
||||||
|
*
|
||||||
|
* \param[in] pond = A pointer to the pointer to the pond that should be
|
||||||
|
* de-referenced. On success the pointer to the pond
|
||||||
|
* is cleared. It must not be NULL and must not point
|
||||||
|
* to NULL.
|
||||||
|
*
|
||||||
|
* \return
|
||||||
|
* ISC_R_SUCCESS = The pond was successfully de-referenced, pond now points
|
||||||
|
* to NULL
|
||||||
|
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
|
||||||
|
* modified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
isc_result_t
|
||||||
|
ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
|
||||||
|
struct ipv6_pond *tmp;
|
||||||
|
|
||||||
|
if ((pond == NULL) || (*pond == NULL)) {
|
||||||
|
log_error("%s(%d): NULL pointer", file, line);
|
||||||
|
return DHCP_R_INVALIDARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = *pond;
|
||||||
|
*pond = NULL;
|
||||||
|
|
||||||
|
tmp->refcnt--;
|
||||||
|
if (tmp->refcnt < 0) {
|
||||||
|
log_error("%s(%d): negative refcnt", file, line);
|
||||||
|
tmp->refcnt = 0;
|
||||||
|
}
|
||||||
|
if (tmp->refcnt == 0) {
|
||||||
|
dfree(tmp, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISC_R_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* unittest moved to server/tests/mdb6_unittest.c */
|
/* unittest moved to server/tests/mdb6_unittest.c */
|
||||||
|
@ -28,7 +28,7 @@ statement.
|
|||||||
Then run the server as root, in debug mode:
|
Then run the server as root, in debug mode:
|
||||||
|
|
||||||
# touch /tmp/test.leases
|
# touch /tmp/test.leases
|
||||||
# dhcpd -cf test-a.conf -lf /tmp/test.leases -d
|
# dhcpd -6 -cf test-a.conf -lf /tmp/test.leases -d
|
||||||
|
|
||||||
You can invoke the scripts then:
|
You can invoke the scripts then:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user