mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-31 06:15:55 +00:00
-n [master]
Add code to support the standards version of DDNS
This commit is contained in:
@@ -62,6 +62,8 @@ struct sockaddr_in sockaddr_broadcast;
|
||||
struct in_addr giaddr;
|
||||
struct data_string default_duid;
|
||||
int duid_type = 0;
|
||||
int duid_v4 = 0;
|
||||
int std_dhcid = 0;
|
||||
|
||||
/* ASSERT_STATE() does nothing now; it used to be
|
||||
assert (state_is == state_shouldbe). */
|
||||
@@ -287,12 +289,9 @@ main(int argc, char **argv) {
|
||||
wanted_ia_na = 0;
|
||||
}
|
||||
wanted_ia_pd++;
|
||||
#endif /* DHCPv6 */
|
||||
} else if (!strcmp(argv[i], "-D")) {
|
||||
if (local_family_set && (local_family == AF_INET)) {
|
||||
usage();
|
||||
}
|
||||
local_family_set = 1;
|
||||
local_family = AF_INET6;
|
||||
duid_v4 = 1;
|
||||
if (++i == argc)
|
||||
usage();
|
||||
if (!strcasecmp(argv[i], "LL")) {
|
||||
@@ -302,7 +301,12 @@ main(int argc, char **argv) {
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
#endif /* DHCPv6 */
|
||||
} else if (!strcmp(argv[i], "-i")) {
|
||||
/* enable DUID support for DHCPv4 clients */
|
||||
duid_v4 = 1;
|
||||
} else if (!strcmp(argv[i], "-I")) {
|
||||
/* enable standard DHCID support for DDNS updates */
|
||||
std_dhcid = 1;
|
||||
} else if (!strcmp(argv[i], "-v")) {
|
||||
quiet = 0;
|
||||
} else if (!strcmp(argv[i], "--version")) {
|
||||
@@ -564,12 +568,13 @@ main(int argc, char **argv) {
|
||||
}
|
||||
srandom(seed + cur_time + (unsigned)getpid());
|
||||
|
||||
/* Start a configuration state machine for each interface. */
|
||||
#ifdef DHCPv6
|
||||
if (local_family == AF_INET6) {
|
||||
/* Establish a default DUID. This may be moved to the
|
||||
* DHCPv4 area later.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Establish a default DUID. We always do so for v6 and
|
||||
* do so if desired for v4 via the -D or -i options
|
||||
*/
|
||||
if ((local_family == AF_INET6) ||
|
||||
((local_family == AF_INET) && (duid_v4 == 1))) {
|
||||
if (default_duid.len == 0) {
|
||||
if (default_duid.buffer != NULL)
|
||||
data_string_forget(&default_duid, MDL);
|
||||
@@ -577,7 +582,11 @@ main(int argc, char **argv) {
|
||||
form_duid(&default_duid, MDL);
|
||||
write_duid(&default_duid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start a configuration state machine for each interface. */
|
||||
#ifdef DHCPv6
|
||||
if (local_family == AF_INET6) {
|
||||
for (ip = interfaces ; ip != NULL ; ip = ip->next) {
|
||||
for (client = ip->client ; client != NULL ;
|
||||
client = client->next) {
|
||||
@@ -709,9 +718,9 @@ static void usage()
|
||||
|
||||
log_fatal("Usage: dhclient "
|
||||
#ifdef DHCPv6
|
||||
"[-4|-6] [-SNTP1dvrx] [-nw] [-p <port>] [-D LL|LLT]\n"
|
||||
"[-4|-6] [-SNTPI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
|
||||
#else /* DHCPv6 */
|
||||
"[-1dvrx] [-nw] [-p <port>]\n"
|
||||
"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
|
||||
#endif /* DHCPv6 */
|
||||
" [-s server-addr] [-cf config-file] "
|
||||
"[-lf lease-file]\n"
|
||||
@@ -2296,24 +2305,24 @@ make_client_options(struct client_state *client, struct client_lease *lease,
|
||||
unsigned i;
|
||||
struct option_cache *oc;
|
||||
struct option *option = NULL;
|
||||
struct buffer *bp = (struct buffer *)0;
|
||||
struct buffer *bp = NULL;
|
||||
|
||||
/* If there are any leftover options, get rid of them. */
|
||||
if (*op)
|
||||
option_state_dereference (op, MDL);
|
||||
option_state_dereference(op, MDL);
|
||||
|
||||
/* Allocate space for options. */
|
||||
option_state_allocate (op, MDL);
|
||||
option_state_allocate(op, MDL);
|
||||
|
||||
/* Send the server identifier if provided. */
|
||||
if (sid)
|
||||
save_option (&dhcp_universe, *op, sid);
|
||||
save_option(&dhcp_universe, *op, sid);
|
||||
|
||||
oc = (struct option_cache *)0;
|
||||
oc = NULL;
|
||||
|
||||
/* Send the requested address if provided. */
|
||||
if (rip) {
|
||||
client -> requested_address = *rip;
|
||||
client->requested_address = *rip;
|
||||
i = DHO_DHCP_REQUESTED_ADDRESS;
|
||||
if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
|
||||
&i, 0, MDL) &&
|
||||
@@ -2321,22 +2330,22 @@ make_client_options(struct client_state *client, struct client_lease *lease,
|
||||
option, MDL)))
|
||||
log_error ("can't make requested address cache.");
|
||||
else {
|
||||
save_option (&dhcp_universe, *op, oc);
|
||||
option_cache_dereference (&oc, MDL);
|
||||
save_option(&dhcp_universe, *op, oc);
|
||||
option_cache_dereference(&oc, MDL);
|
||||
}
|
||||
option_dereference(&option, MDL);
|
||||
} else {
|
||||
client -> requested_address.len = 0;
|
||||
client->requested_address.len = 0;
|
||||
}
|
||||
|
||||
i = DHO_DHCP_MESSAGE_TYPE;
|
||||
if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0,
|
||||
MDL) &&
|
||||
make_const_option_cache(&oc, NULL, type, 1, option, MDL)))
|
||||
log_error ("can't make message type.");
|
||||
log_error("can't make message type.");
|
||||
else {
|
||||
save_option (&dhcp_universe, *op, oc);
|
||||
option_cache_dereference (&oc, MDL);
|
||||
save_option(&dhcp_universe, *op, oc);
|
||||
option_cache_dereference(&oc, MDL);
|
||||
}
|
||||
option_dereference(&option, MDL);
|
||||
|
||||
@@ -2349,8 +2358,8 @@ make_client_options(struct client_state *client, struct client_lease *lease,
|
||||
if (prl[i]->universe == &dhcp_universe)
|
||||
len++;
|
||||
|
||||
if (!buffer_allocate (&bp, len, MDL))
|
||||
log_error ("can't make parameter list buffer.");
|
||||
if (!buffer_allocate(&bp, len, MDL))
|
||||
log_error("can't make parameter list buffer.");
|
||||
else {
|
||||
unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST;
|
||||
|
||||
@@ -2364,15 +2373,69 @@ make_client_options(struct client_state *client, struct client_lease *lease,
|
||||
&code, 0, MDL) &&
|
||||
make_const_option_cache(&oc, &bp, NULL, len,
|
||||
option, MDL)))
|
||||
log_error ("can't make option cache");
|
||||
log_error("can't make option cache");
|
||||
else {
|
||||
save_option (&dhcp_universe, *op, oc);
|
||||
option_cache_dereference (&oc, MDL);
|
||||
save_option(&dhcp_universe, *op, oc);
|
||||
option_cache_dereference(&oc, MDL);
|
||||
}
|
||||
option_dereference(&option, MDL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If requested (duid_v4 == 1) add an RFC4361 compliant client-identifier
|
||||
* This can be overridden by including a client id in the configuration
|
||||
* file.
|
||||
*/
|
||||
if (duid_v4 == 1) {
|
||||
struct data_string client_identifier;
|
||||
int hw_idx, hw_len;
|
||||
|
||||
memset(&client_identifier, 0, sizeof(client_identifier));
|
||||
client_identifier.len = 1 + 4 + default_duid.len;
|
||||
if (!buffer_allocate(&client_identifier.buffer,
|
||||
client_identifier.len, MDL))
|
||||
log_fatal("no memory for default DUID!");
|
||||
client_identifier.data = client_identifier.buffer->data;
|
||||
|
||||
i = DHO_DHCP_CLIENT_IDENTIFIER;
|
||||
|
||||
/* Client-identifier type : 1 byte */
|
||||
*client_identifier.buffer->data = 255;
|
||||
|
||||
/* IAID : 4 bytes
|
||||
* we use the low 4 bytes from the interface address
|
||||
*/
|
||||
if (client->interface->hw_address.hlen > 4) {
|
||||
hw_idx = client->interface->hw_address.hlen - 4;
|
||||
hw_len = 4;
|
||||
} else {
|
||||
hw_idx = 0;
|
||||
hw_len = client->interface->hw_address.hlen;
|
||||
}
|
||||
memcpy(&client_identifier.buffer->data + 5 - hw_len,
|
||||
client->interface->hw_address.hbuf + hw_idx,
|
||||
hw_len);
|
||||
|
||||
/* Add the default duid */
|
||||
memcpy(&client_identifier.buffer->data+(1+4),
|
||||
default_duid.data, default_duid.len);
|
||||
|
||||
/* And save the option */
|
||||
if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash,
|
||||
&i, 0, MDL) &&
|
||||
make_const_option_cache(&oc, NULL,
|
||||
(u_int8_t *)client_identifier.data,
|
||||
client_identifier.len,
|
||||
option, MDL)))
|
||||
log_error ("can't make requested client id cache..");
|
||||
else {
|
||||
save_option (&dhcp_universe, *op, oc);
|
||||
option_cache_dereference (&oc, MDL);
|
||||
}
|
||||
option_dereference(&option, MDL);
|
||||
}
|
||||
|
||||
/* Run statements that need to be run on transmission. */
|
||||
if (client->config->on_transmission)
|
||||
execute_statements_in_scope(NULL, NULL, NULL, client,
|
||||
@@ -2778,6 +2841,69 @@ write_options(struct client_state *client, struct option_state *options,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "best" default DUID, since we cannot predict any information
|
||||
* about the system (such as whether or not the hardware addresses are
|
||||
* integrated into the motherboard or similar), is the "LLT", link local
|
||||
* plus time, DUID. For real stateless "LL" is better.
|
||||
*
|
||||
* Once generated, this duid is stored into the state database, and
|
||||
* retained across restarts.
|
||||
*
|
||||
* For the time being, there is probably a different state database for
|
||||
* every daemon, so this winds up being a per-interface identifier...which
|
||||
* is not how it is intended. Upcoming rearchitecting the client should
|
||||
* address this "one daemon model."
|
||||
*/
|
||||
void
|
||||
form_duid(struct data_string *duid, const char *file, int line)
|
||||
{
|
||||
struct interface_info *ip;
|
||||
int len;
|
||||
|
||||
/* For now, just use the first interface on the list. */
|
||||
ip = interfaces;
|
||||
|
||||
if (ip == NULL)
|
||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||
|
||||
if ((ip->hw_address.hlen == 0) ||
|
||||
(ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
|
||||
log_fatal("Impossible hardware address length at %s:%d.", MDL);
|
||||
|
||||
if (duid_type == 0)
|
||||
duid_type = stateless ? DUID_LL : DUID_LLT;
|
||||
|
||||
/*
|
||||
* 2 bytes for the 'duid type' field.
|
||||
* 2 bytes for the 'htype' field.
|
||||
* (DUID_LLT) 4 bytes for the 'current time'.
|
||||
* enough bytes for the hardware address (note that hw_address has
|
||||
* the 'htype' on byte zero).
|
||||
*/
|
||||
len = 4 + (ip->hw_address.hlen - 1);
|
||||
if (duid_type == DUID_LLT)
|
||||
len += 4;
|
||||
if (!buffer_allocate(&duid->buffer, len, MDL))
|
||||
log_fatal("no memory for default DUID!");
|
||||
duid->data = duid->buffer->data;
|
||||
duid->len = len;
|
||||
|
||||
/* Basic Link Local Address type of DUID. */
|
||||
if (duid_type == DUID_LLT) {
|
||||
putUShort(duid->buffer->data, DUID_LLT);
|
||||
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||
putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
|
||||
memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
|
||||
ip->hw_address.hlen - 1);
|
||||
} else {
|
||||
putUShort(duid->buffer->data, DUID_LL);
|
||||
putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
|
||||
memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
|
||||
ip->hw_address.hlen - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the default DUID to the lease store. */
|
||||
static isc_result_t
|
||||
write_duid(struct data_string *duid)
|
||||
@@ -3991,6 +4117,7 @@ client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb)
|
||||
struct option_cache *oc;
|
||||
int ignorep;
|
||||
int result;
|
||||
int ddns_v4_type;
|
||||
isc_result_t rcode;
|
||||
|
||||
/* If we didn't send an FQDN option, we certainly aren't going to
|
||||
@@ -4033,48 +4160,82 @@ client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb)
|
||||
&global_scope, oc, MDL))
|
||||
return ISC_R_SUCCESS;
|
||||
|
||||
/* If this is a DHCPv6 client update, make a dhcid string out of
|
||||
* the DUID. If this is a DHCPv4 client update, choose either
|
||||
* the client identifier, if there is one, or the interface's
|
||||
* MAC address.
|
||||
/*
|
||||
* Construct the DHCID value for use in the DDNS update process
|
||||
* We have the newer standard version and the older interim version
|
||||
* chosen by the '-I' option. The interim version is left as is
|
||||
* for backwards compatibility. The standard version is based on
|
||||
* RFC 4701 section 3.3
|
||||
*/
|
||||
|
||||
result = 0;
|
||||
POST(result);
|
||||
memset(&client_identifier, 0, sizeof(client_identifier));
|
||||
|
||||
if (std_dhcid == 1) {
|
||||
/* standard style */
|
||||
ddns_cb->dhcid_class = dns_rdatatype_dhcid;
|
||||
ddns_v4_type = 1;
|
||||
} else {
|
||||
/* interim style */
|
||||
ddns_cb->dhcid_class = dns_rdatatype_txt;
|
||||
/* for backwards compatibility */
|
||||
ddns_v4_type = DHO_DHCP_CLIENT_IDENTIFIER;
|
||||
}
|
||||
if (client->active_lease != NULL) {
|
||||
if (((oc =
|
||||
lookup_option(&dhcpv6_universe, client->sent_options,
|
||||
D6O_CLIENTID)) != NULL) &&
|
||||
evaluate_option_cache(&client_identifier, NULL, NULL,
|
||||
client, client->sent_options, NULL,
|
||||
/* V6 request, get the client identifier, then
|
||||
* construct the dhcid for either standard
|
||||
* or interim */
|
||||
if (((oc = lookup_option(&dhcpv6_universe,
|
||||
client->sent_options,
|
||||
D6O_CLIENTID)) != NULL) &&
|
||||
evaluate_option_cache(&client_identifier, NULL,
|
||||
NULL, client,
|
||||
client->sent_options, NULL,
|
||||
&global_scope, oc, MDL)) {
|
||||
/* RFC4701 defines type '2' as being for the DUID
|
||||
* field. We aren't using RFC4701 DHCID RR's yet,
|
||||
* but this is as good a value as any.
|
||||
*/
|
||||
result = get_dhcid(&ddns_cb->dhcid, 2,
|
||||
result = get_dhcid(ddns_cb, 2,
|
||||
client_identifier.data,
|
||||
client_identifier.len);
|
||||
data_string_forget(&client_identifier, MDL);
|
||||
} else
|
||||
log_fatal("Impossible condition at %s:%d.", MDL);
|
||||
} else {
|
||||
if (((oc =
|
||||
lookup_option(&dhcp_universe, client->sent_options,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) &&
|
||||
evaluate_option_cache(&client_identifier, NULL, NULL,
|
||||
client, client->sent_options, NULL,
|
||||
/*
|
||||
* V4 request, use the client id if there is one or the
|
||||
* mac address if there isn't. If we have a client id
|
||||
* we check to see if it is an embedded DUID.
|
||||
*/
|
||||
if (((oc = lookup_option(&dhcp_universe,
|
||||
client->sent_options,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) &&
|
||||
evaluate_option_cache(&client_identifier, NULL,
|
||||
NULL, client,
|
||||
client->sent_options, NULL,
|
||||
&global_scope, oc, MDL)) {
|
||||
result = get_dhcid(&ddns_cb->dhcid,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER,
|
||||
client_identifier.data,
|
||||
client_identifier.len);
|
||||
if ((std_dhcid == 1) && (duid_v4 == 1) &&
|
||||
(client_identifier.data[0] == 255)) {
|
||||
/*
|
||||
* This appears to be an embedded DUID,
|
||||
* extract it and treat it as such
|
||||
*/
|
||||
if (client_identifier.len <= 5)
|
||||
log_fatal("Impossible condition at %s:%d.",
|
||||
MDL);
|
||||
result = get_dhcid(ddns_cb, 2,
|
||||
client_identifier.data + 5,
|
||||
client_identifier.len - 5);
|
||||
} else {
|
||||
result = get_dhcid(ddns_cb, ddns_v4_type,
|
||||
client_identifier.data,
|
||||
client_identifier.len);
|
||||
}
|
||||
data_string_forget(&client_identifier, MDL);
|
||||
} else
|
||||
result = get_dhcid(&ddns_cb->dhcid, 0,
|
||||
result = get_dhcid(ddns_cb, 0,
|
||||
client->interface->hw_address.hbuf,
|
||||
client->interface->hw_address.hlen);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
@@ -4342,3 +4503,4 @@ add_reject(struct packet *packet) {
|
||||
*/
|
||||
log_info("Server added to list of rejected servers.");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user