summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELNOTES8
-rw-r--r--common/conflex.c4
-rw-r--r--common/dhcp-options.516
-rw-r--r--common/parse.c30
-rw-r--r--common/tree.c124
-rw-r--r--includes/dhcp6.h2
-rw-r--r--includes/dhcpd.h4
-rw-r--r--includes/dhctoken.h4
-rw-r--r--includes/tree.h7
-rw-r--r--relay/dhcrelay.811
-rw-r--r--relay/dhcrelay.c37
-rw-r--r--server/confpars.c22
-rw-r--r--server/dhcpd.conf.511
-rw-r--r--server/dhcpv6.c18
-rw-r--r--server/mdb.c52
15 files changed, 330 insertions, 20 deletions
diff --git a/RELNOTES b/RELNOTES
index 1eff1dcf..d0652ab6 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -105,6 +105,14 @@ work on other platforms. Please report any problems and suggested fixes to
This is "failover peer <name>: Both servers normal."
[ISC-Bugs 33208]
+- Add support for accessing options from v6 relays. The v6relay
+ statement allows the administrator to choose which relay to
+ use when searching for an option, see the dhcp-options man page
+ for a description. The host-identifer option has also been
+ updated to support the use of relay options see the dhcpd.conf
+ man page for a description.
+ [ISC-Bugs #19598]
+
Changes since 4.2.5
- Address static analysis warnings.
diff --git a/common/conflex.c b/common/conflex.c
index 595ac4d5..9cdb88e5 100644
--- a/common/conflex.c
+++ b/common/conflex.c
@@ -1501,6 +1501,10 @@ intern(char *atom, enum dhcp_token dfv) {
return UPDATE;
break;
case 'v':
+ if (!strcasecmp (atom + 1, "6relay"))
+ return V6RELAY;
+ if (!strcasecmp (atom + 1, "6relopt"))
+ return V6RELOPT;
if (!strcasecmp (atom + 1, "endor-class"))
return VENDOR_CLASS;
if (!strcasecmp (atom + 1, "endor"))
diff --git a/common/dhcp-options.5 b/common/dhcp-options.5
index f57fd731..7dee4117 100644
--- a/common/dhcp-options.5
+++ b/common/dhcp-options.5
@@ -1712,6 +1712,22 @@ The \fBlq-relay-data\fR option is used internally by for lease query.
.PP
The \fBlq-client-link\fR option is used internally by for lease query.
.RE
+.SH ACCESSING DHCPV6 RELAY OPTIONS
+.PP
+.B v6relay (\fBrelay-number\f, \fBoption\f)
+This option allows access to an option that has been added to a packet
+by a relay agent. Relay-number value selects the relay to examine
+and option is the option to find. In DHCPv6 each relay encapsulates
+the entire previous message into an option, adds its own options (if
+any) and sends the result onwards. The RFC specifies a limit of 32
+hops. A relay-number of 0 is a no-op and means don't look at the relays.
+1 is the relay that is closest to the client, 2 would be the next in
+from the client and so on. Any value greater than the max number of hops
+is which is closest to the server independent of number. To use this
+option in a class statement you would have something like this:
+.PP
+match if v6relay(1, option dhcp6.subscriber-id) = "client_1";
+.RE
.PP
.RE
.SH DEFINING NEW OPTIONS
diff --git a/common/parse.c b/common/parse.c
index d931b97c..dd40bdbf 100644
--- a/common/parse.c
+++ b/common/parse.c
@@ -3463,6 +3463,8 @@ int parse_boolean (cfile)
* HARDWARE |
* PACKET LPAREN numeric-expression COMMA
* numeric-expression RPAREN |
+ * V6RELAY LPAREN numeric-expression COMMA
+ * data-expression RPAREN |
* STRING |
* colon_separated_hex_list
*/
@@ -4333,6 +4335,34 @@ int parse_non_binary (expr, cfile, lose, context)
goto norparen;
break;
+ case V6RELAY:
+ skip_token(&val, NULL, cfile);
+ if (!expression_allocate (expr, MDL))
+ log_fatal ("can't allocate expression");
+ (*expr)->op = expr_v6relay;
+
+ token = next_token (&val, NULL, cfile);
+ if (token != LPAREN)
+ goto nolparen;
+
+ if (!parse_numeric_expression (&(*expr)->data.v6relay.relay,
+ cfile, lose))
+ goto nodata;
+
+ token = next_token (&val, NULL, cfile);
+ if (token != COMMA)
+ goto nocomma;
+
+ if (!parse_data_expression (&(*expr)->data.v6relay.roption,
+ cfile, lose))
+ goto nodata;
+
+ token = next_token (&val, NULL, cfile);
+
+ if (token != RPAREN)
+ goto norparen;
+ break;
+
/* Not a valid start to an expression... */
default:
if (token != NAME && token != NUMBER_OR_NAME)
diff --git a/common/tree.c b/common/tree.c
index ba41bbe7..7bb5ee0b 100644
--- a/common/tree.c
+++ b/common/tree.c
@@ -1072,6 +1072,7 @@ int evaluate_boolean_expression (result, packet, lease, client_state,
case expr_filename:
case expr_sname:
case expr_gethostname:
+ case expr_v6relay:
log_error ("Data opcode in evaluate_boolean_expression: %d",
expr -> op);
return 0;
@@ -1136,6 +1137,8 @@ int evaluate_data_expression (result, packet, lease, client_state,
struct binding *binding;
unsigned char *s;
struct binding_value *bv;
+ struct packet *relay_packet;
+ struct option_state *relay_options;
switch (expr -> op) {
/* Extract N bytes starting at byte M of a data string. */
@@ -1213,6 +1216,7 @@ int evaluate_data_expression (result, packet, lease, client_state,
result -> data += data.len - len;
result -> len = len;
}
+
data_string_forget (&data, MDL);
}
@@ -1224,6 +1228,7 @@ int evaluate_data_expression (result, packet, lease, client_state,
? print_hex_2 (result -> len, result -> data, 30)
: "NULL"));
#endif
+
return s0 && s1;
/* Convert string to lowercase. */
@@ -1294,8 +1299,9 @@ int evaluate_data_expression (result, packet, lease, client_state,
s1 ? print_hex_2(result->len, result->data, 30)
: "NULL");
#endif
- if (s0)
+ if (s0)
data_string_forget(&data, MDL);
+
return s1;
/* Extract an option. */
@@ -2028,6 +2034,79 @@ int evaluate_data_expression (result, packet, lease, client_state,
data_string_forget(result, MDL);
return 0;
+ /* Find an option within a v6relay context
+ *
+ * The numeric expression in relay indicates which relay
+ * to try and use as the context. The relays are numbered
+ * 1 to 32 with 1 being the one closest to the client and
+ * 32 closest to the server. A value of greater than 33
+ * indicates using the one closest to the server whatever
+ * the count. A value of 0 indicates not using the relay
+ * options, this is included for completeness and consistency
+ * with the host-identier code.
+ *
+ * The data expression in roption is evaluated in that
+ * context and the result returned.
+ */
+ case expr_v6relay:
+ len = 0;
+ s1 = 0;
+ memset (&data, 0, sizeof data);
+
+ /* Evaluate the relay count */
+ s0 = evaluate_numeric_expression(&len, packet, lease,
+ client_state,
+ in_options, cfg_options,
+ scope,
+ expr->data.v6relay.relay);
+
+ /* no number or an obviously invalid number */
+ if ((s0 == 0) ||
+ ((len > 0) &&
+ ((packet == NULL) ||
+ (packet->dhcpv6_container_packet == NULL)))) {
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug("data: v6relay(%d) = NULL", len);
+#endif
+ return (0);
+ }
+
+ /* Find the correct packet for the requested relay */
+ i = len;
+ relay_packet = packet;
+ relay_options = in_options;
+ while ((i != 0) &&
+ (relay_packet->dhcpv6_container_packet != NULL)) {
+ relay_packet = relay_packet->dhcpv6_container_packet;
+ relay_options = relay_packet->options;
+ i--;
+ }
+ /* We wanted a specific relay but were unable to find it */
+ if ((len <= MAX_V6RELAY_HOPS) && (i != 0)) {
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug("data: v6relay(%d) = NULL", len);
+#endif
+ return (0);
+ }
+
+ s1 = evaluate_data_expression(&data, relay_packet, lease,
+ client_state, relay_options,
+ cfg_options, scope,
+ expr->data.v6relay.roption,
+ MDL);
+
+ if (s1) {
+ data_string_copy(result, &data, file, line);
+ data_string_forget(&data, MDL);
+ }
+
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug("data: v6relay(%d) = %s", len,
+ s1 ? print_hex_3(result->len, result->data, 30)
+ : "NULL");
+#endif
+ return (s1);
+
case expr_check:
case expr_equal:
case expr_not_equal:
@@ -2147,6 +2226,7 @@ int evaluate_numeric_expression (result, packet, lease, client_state,
case expr_leased_address:
case expr_null:
case expr_gethostname:
+ case expr_v6relay:
log_error ("Data opcode in evaluate_numeric_expression: %d",
expr -> op);
return 0;
@@ -2849,6 +2929,16 @@ void expression_dereference (eptr, file, line)
fundef_dereference (&expr -> data.func, file, line);
break;
+ case expr_v6relay:
+ if (expr->data.v6relay.relay)
+ expression_dereference(&expr->data.v6relay.relay,
+ file, line);
+
+ if (expr->data.v6relay.roption)
+ expression_dereference(&expr->data.v6relay.roption,
+ file, line);
+ break;
+
/* No subexpressions. */
case expr_leased_address:
case expr_lease_time:
@@ -2913,7 +3003,8 @@ int is_data_expression (expr)
expr->op == expr_leased_address ||
expr->op == expr_config_option ||
expr->op == expr_null ||
- expr->op == expr_gethostname);
+ expr->op == expr_gethostname ||
+ expr->op == expr_v6relay);
}
int is_numeric_expression (expr)
@@ -2951,7 +3042,8 @@ int is_compound_expression (expr)
expr -> op == expr_config_option ||
expr -> op == expr_extract_int8 ||
expr -> op == expr_extract_int16 ||
- expr -> op == expr_extract_int32);
+ expr -> op == expr_extract_int32 ||
+ expr -> op == expr_v6relay);
}
static int op_val (enum expr_op);
@@ -3011,6 +3103,7 @@ static int op_val (op)
case expr_binary_xor:
case expr_client_state:
case expr_gethostname:
+ case expr_v6relay:
return 100;
case expr_equal:
@@ -3103,6 +3196,7 @@ enum expression_context op_context (op)
case expr_funcall:
case expr_function:
case expr_gethostname:
+ case expr_v6relay:
return context_any;
case expr_equal:
@@ -3568,6 +3662,19 @@ int write_expression (file, expr, col, indent, firstp)
col = token_print_indent(file, col, indent, "", "", ")");
break;
+ case expr_v6relay:
+ col = token_print_indent(file, col, indent, "", "",
+ "v6relay");
+ col = token_print_indent(file, col, indent, " ", "", "(");
+ scol = col;
+ col = write_expression(file, expr->data.v6relay.relay,
+ col, scol, 1);
+ col = token_print_indent (file, col, scol, "", " ", ",");
+ col = write_expression(file, expr->data.v6relay.roption,
+ col, scol, 0);
+ col = token_print_indent(file, col, indent, "", "", ")");
+ break;
+
default:
log_fatal ("invalid expression type in print_expression: %d",
expr -> op);
@@ -3765,6 +3872,17 @@ int data_subexpression_length (int *rv,
*rv = lrhs;
return 1;
+ case expr_v6relay:
+ clhs = data_subexpression_length (&llhs,
+ expr -> data.v6relay.relay);
+ crhs = data_subexpression_length (&lrhs,
+ expr -> data.v6relay.roption);
+ if (crhs == 0 || clhs == 0)
+ return 0;
+ *rv = llhs + lrhs;
+ return 1;
+ break;
+
case expr_binary_to_ascii:
case expr_config_option:
case expr_host_decl_name:
diff --git a/includes/dhcp6.h b/includes/dhcp6.h
index 03db160e..94ddc592 100644
--- a/includes/dhcp6.h
+++ b/includes/dhcp6.h
@@ -3,6 +3,7 @@
DHCPv6 Protocol structures... */
/*
+ * Copyright (c) 2013 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2006-2009 by Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
@@ -193,6 +194,7 @@ struct dhcpv6_relay_packet {
unsigned char peer_address[16];
unsigned char options[FLEXIBLE_ARRAY_MEMBER];
};
+#define MAX_V6RELAY_HOPS 32
/* Leasequery query-types (RFC 5007) */
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 6a538555..c74fab35 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -882,6 +882,10 @@ struct host_decl {
#define HOST_DECL_DELETED 1
#define HOST_DECL_DYNAMIC 2
#define HOST_DECL_STATIC 4
+ /* For v6 the host-identifer option can specify which relay
+ to use when trying to look up an option. We store the
+ value here. */
+ int relays;
};
struct permit {
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 4822279c..7b5770d6 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -371,7 +371,9 @@ enum dhcp_token {
PRIMARY6 = 666,
SECONDARY6 = 667,
TOKEN_INFINIBAND = 668,
- POOL6 = 669
+ POOL6 = 669,
+ V6RELAY = 670,
+ V6RELOPT = 671
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
diff --git a/includes/tree.h b/includes/tree.h
index e4a78cd1..fd5f7fc5 100644
--- a/includes/tree.h
+++ b/includes/tree.h
@@ -196,7 +196,8 @@ enum expr_op {
expr_lcase,
expr_regex_match,
expr_iregex_match,
- expr_gethostname
+ expr_gethostname,
+ expr_v6relay
};
struct expression {
@@ -279,6 +280,10 @@ struct expression {
struct expression *arglist;
} funcall;
struct fundef *func;
+ struct {
+ struct expression *relay;
+ struct expression *roption;
+ } v6relay;
} data;
int flags;
# define EXPR_EPHEMERAL 1
diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8
index 21c53bc0..d3f4593b 100644
--- a/relay/dhcrelay.8
+++ b/relay/dhcrelay.8
@@ -1,6 +1,6 @@
.\" dhcrelay.8
.\"
-.\" Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2009-2013 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1997-2003 by Internet Software Consortium
.\"
@@ -103,6 +103,10 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent
[
.B --no-pid
]
+[
+.B -s
+.I subscriber-id
+]
.B -l
.I lower0
[
@@ -223,6 +227,11 @@ in use, to disambiguate between them. The \fB-I\fR option causes
dhcrelay to send the option even if there is only one downstream
interface.
.TP
+-s subscriber-id
+Add an option with the specified subscriber-id into the packet. This
+feature is for testing rather than production as it will put the same
+subscriber-id into the packet for all clients.
+.TP
-l [\fIaddress%\fR]\fIifname\fR[\fI#index\fR]
Specifies the ``lower'' network interface for DHCPv6 relay mode: the
interface on which queries will be received from clients or from other
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index b2d7bd90..b65731ce 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -116,6 +116,14 @@ struct stream_list {
static struct stream_list *parse_downstream(char *);
static struct stream_list *parse_upstream(char *);
static void setup_streams(void);
+
+/*
+ * A pointer to a subscriber id to add to the message we forward.
+ * This is primarily for testing purposes as we only have one id
+ * for the entire relay and don't determine one per client which
+ * would be more useful.
+ */
+char *dhcrelay_sub_id = NULL;
#endif
static void do_relay4(struct interface_info *, struct dhcp_packet *,
@@ -147,7 +155,8 @@ static const char url[] =
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n" \
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
-" [-pf <pid-file>] [--no-pid]\n"\
+" [-pf <pid-file>] [--no-pid]\n" \
+" [-s <subscriber-id>]\n" \
" -l lower0 [ ... -l lowerN]\n" \
" -u upper0 [ ... -u upperN]\n" \
" lower (client link): [address%%]interface[#index]\n" \
@@ -155,7 +164,7 @@ static const char url[] =
#else
#define DHCRELAY_USAGE \
"Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
-" [-pf <pid-file>] [--no-pid]\n"\
+" [-pf <pid-file>] [--no-pid]\n" \
" [-m append|replace|forward|discard]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n"
@@ -362,6 +371,15 @@ main(int argc, char **argv) {
sl = parse_upstream(argv[i]);
sl->next = upstreams;
upstreams = sl;
+ } else if (!strcmp(argv[i], "-s")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ if (++i == argc)
+ usage();
+ dhcrelay_sub_id = argv[i];
#endif
} else if (!strcmp(argv[i], "-pf")) {
if (++i == argc)
@@ -1341,6 +1359,7 @@ setup_streams(void) {
*/
static const int required_forw_opts[] = {
D6O_INTERFACE_ID,
+ D6O_SUBSCRIBER_ID,
D6O_RELAY_MSG,
0
};
@@ -1451,6 +1470,20 @@ process_up6(struct packet *packet, struct stream_list *dp) {
}
}
+ /* Add a subscriber-id if desired. */
+ /* This is for testing rather than general use */
+ if (dhcrelay_sub_id != NULL) {
+ if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
+ (unsigned char *) dhcrelay_sub_id,
+ strlen(dhcrelay_sub_id),
+ D6O_SUBSCRIBER_ID, 0)) {
+ log_error("Can't save subsriber-id.");
+ option_state_dereference(&opts, MDL);
+ return;
+ }
+ }
+
+
/* Add the relay-msg carrying the packet. */
if (!save_option_buffer(&dhcpv6_universe, opts,
NULL, (unsigned char *) packet->raw,
diff --git a/server/confpars.c b/server/confpars.c
index d27ff448..fa33a0ca 100644
--- a/server/confpars.c
+++ b/server/confpars.c
@@ -1974,9 +1974,27 @@ void parse_host_declaration (cfile, group)
}
skip_token(&val, NULL, cfile);
token = next_token(&val, NULL, cfile);
- if (token != OPTION) {
+ if (token == V6RELOPT) {
+ token = next_token(&val, NULL, cfile);
+ if (token != NUMBER) {
+ parse_warn(cfile,
+ "host-identifier v6relopt "
+ "must have a number");
+ skip_to_rbrace(cfile, 1);
+ break;
+ }
+ host->relays = atoi(val);
+ if (host->relays < 0) {
+ parse_warn(cfile,
+ "host-identifer v6relopt "
+ "must have a number >= 0");
+ skip_to_rbrace(cfile, 1);
+ break;
+ }
+ } else if (token != OPTION) {
parse_warn(cfile,
- "host-identifier must be an option");
+ "host-identifier must be an option"
+ " or v6relopt");
skip_to_rbrace(cfile, 1);
break;
}
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 8a132b8d..84603c0f 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -2271,6 +2271,10 @@ statement
.PP
.B host-identifier option \fIoption-name option-data\fB;\fR
.PP
+or
+.PP
+.B host-identifier v6relopt \fInumber option-name option-data\fB;\fR
+.PP
This identifies a DHCPv6 client in a
.I host
statement.
@@ -2279,7 +2283,12 @@ is any option, and
.I option-data
is the value for the option that the client will send. The
.I option-data
-must be a constant value.
+must be a constant value. In the v6relopts case the additional number
+is the relay to examine for the specified option name and value. The
+values are the same as for the v6relay option. 0 is a no-op, 1 is the
+relay closest to the client, 2 the next one in and so on. Values that
+are larger than the maximum number of relays (currently 32) indicate the
+relay closest to the server independent of number.
.RE
.PP
The
diff --git a/server/dhcpv6.c b/server/dhcpv6.c
index 6daba5e4..45ea753c 100644
--- a/server/dhcpv6.c
+++ b/server/dhcpv6.c
@@ -6299,41 +6299,54 @@ static void
build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
memset(reply, 0, sizeof(*reply));
- /* Classify the client */
- classify_client(packet);
+ /* I would like to classify the client once here, but
+ * as I don't want to classify all of the incoming packets
+ * I need to do it before handling specific types.
+ * We don't need to classify if we are tossing the packet
+ * or if it is a relay - the classification step will get
+ * done when we process the inner client packet.
+ */
switch (packet->dhcpv6_msg_type) {
case DHCPV6_SOLICIT:
+ classify_client(packet);
dhcpv6_solicit(reply, packet);
break;
case DHCPV6_ADVERTISE:
dhcpv6_discard(packet);
break;
case DHCPV6_REQUEST:
+ classify_client(packet);
dhcpv6_request(reply, packet);
break;
case DHCPV6_CONFIRM:
+ classify_client(packet);
dhcpv6_confirm(reply, packet);
break;
case DHCPV6_RENEW:
+ classify_client(packet);
dhcpv6_renew(reply, packet);
break;
case DHCPV6_REBIND:
+ classify_client(packet);
dhcpv6_rebind(reply, packet);
break;
case DHCPV6_REPLY:
dhcpv6_discard(packet);
break;
case DHCPV6_RELEASE:
+ classify_client(packet);
dhcpv6_release(reply, packet);
break;
case DHCPV6_DECLINE:
+ classify_client(packet);
dhcpv6_decline(reply, packet);
break;
case DHCPV6_RECONFIGURE:
dhcpv6_discard(packet);
break;
case DHCPV6_INFORMATION_REQUEST:
+ classify_client(packet);
dhcpv6_information_request(reply, packet);
break;
case DHCPV6_RELAY_FORW:
@@ -6343,6 +6356,7 @@ build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
dhcpv6_discard(packet);
break;
case DHCPV6_LEASEQUERY:
+ classify_client(packet);
dhcpv6_leasequery(reply, packet);
break;
case DHCPV6_LEASEQUERY_REPLY:
diff --git a/server/mdb.c b/server/mdb.c
index ba2c3d32..51c9566e 100644
--- a/server/mdb.c
+++ b/server/mdb.c
@@ -55,10 +55,18 @@ lease_id_hash_t *lease_hw_addr_hash;
* identifier. Because of this, we store a list with an entry for
* each option type. Each of these has a hash table, which contains
* hash of the option data.
+ *
+ * For v6 we also include a relay count - this specifies which
+ * relay to check for the requested option. As each different
+ * value of relays creates a new instance admins should use the
+ * same value across each option for all host-identifers.
+ * A value of 0 indicates that we aren't doing relay options
+ * and should simply look in the current option list.
*/
typedef struct host_id_info {
struct option *option;
host_hash_t *values_hash;
+ int relays;
struct host_id_info *next;
} host_id_info_t;
@@ -146,11 +154,12 @@ static int find_uid_statement (struct executable_statement *esp,
static host_id_info_t *
-find_host_id_info(unsigned int option_code) {
+find_host_id_info(unsigned int option_code, int relays) {
host_id_info_t *p;
- for (p=host_id_info; p != NULL; p = p->next) {
- if (p->option->code == option_code) {
+ for (p = host_id_info; p != NULL; p = p->next) {
+ if ((p->option->code == option_code) &&
+ (p->relays == relays)) {
break;
}
}
@@ -369,7 +378,8 @@ isc_result_t enter_host (hd, dynamicp, commit)
* Look for the host identifier information for this option,
* and create a new entry if there is none.
*/
- h_id_info = find_host_id_info(hd->host_id_option->code);
+ h_id_info = find_host_id_info(hd->host_id_option->code,
+ hd->relays);
if (h_id_info == NULL) {
h_id_info = dmalloc(sizeof(*h_id_info), MDL);
if (h_id_info == NULL) {
@@ -383,6 +393,7 @@ isc_result_t enter_host (hd, dynamicp, commit)
log_fatal("No memory for host-identifier "
"option hash.");
}
+ h_id_info->relays = hd->relays;
h_id_info->next = host_id_info;
host_id_info = h_id_info;
}
@@ -638,14 +649,41 @@ find_hosts_by_option(struct host_decl **hp,
struct option_cache *oc;
struct data_string data;
int found;
+ struct packet *relay_packet;
+ struct option_state *relay_state;
for (p = host_id_info; p != NULL; p = p->next) {
+ relay_packet = packet;
+ relay_state = opt_state;
+
+ /* If this option block is for a relay (relays != 0)
+ * and we are processing the main options and not
+ * options from the IA (packet->options == opt_state)
+ * try to find the proper relay
+ */
+ if ((p->relays != 0) && (packet->options == opt_state)) {
+ int i = p->relays;
+ while ((i != 0) &&
+ (relay_packet->dhcpv6_container_packet != NULL)) {
+ relay_packet =
+ relay_packet->dhcpv6_container_packet;
+ i--;
+ }
+ /* We wanted a specific relay but were
+ * unable to find it */
+ if ((p->relays <= MAX_V6RELAY_HOPS) && (i != 0))
+ continue;
+
+ relay_state = relay_packet->options;
+ }
+
oc = lookup_option(p->option->universe,
- opt_state, p->option->code);
+ relay_state, p->option->code);
if (oc != NULL) {
memset(&data, 0, sizeof(data));
- if (!evaluate_option_cache(&data, packet, NULL, NULL,
- opt_state, NULL,
+
+ if (!evaluate_option_cache(&data, relay_packet, NULL,
+ NULL, relay_state, NULL,
&global_scope, oc,
MDL)) {
log_error("Error evaluating option cache");