mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-15 18:03:30 +00:00
167 lines
7.0 KiB
Diff
167 lines
7.0 KiB
Diff
From 93ac8f9d469ff08d41170eb6934842b3626d5fdd Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
|
Date: Wed, 23 Dec 2015 22:10:44 +0100
|
|
Subject: [PATCH] DHCPv6: Honor assigning IPv6 address based on MAC address
|
|
|
|
Currently IPv6 addresses are assigned to tuple (IAID, DUID). When system
|
|
changes IAID/DUID then old assigned IPv6 address cannot be reused, even
|
|
when in config file was DHCPv6 assignment based on MAC address (and not on
|
|
DUID).
|
|
|
|
IAID/DUID is changed when rebooting from one operating system to another;
|
|
or after reinstalling system. In reality it is normal that DUID of some
|
|
machine is changed, so people rather assign also IPv6 addresses based on
|
|
MAC address.
|
|
|
|
So assigning IPv6 based on MAC address in dnsmasq is currently semi-broken.
|
|
|
|
This patch tries to fix it and honors IPv6 config rules with MAC address,
|
|
to always assign particular IPv6 address to specific MAC address (when
|
|
configured). And ignores the fact if IAID/DUID was changed.
|
|
|
|
Normally IPv6 address should be assigned by IAID/DUID (which also state
|
|
DHCPv6 RFCs), but dnsmasq has already some support for assigning IPv6
|
|
address based on MAC address, when users configured in config file.
|
|
|
|
So this patch just tries to fix above problem for user configuration with
|
|
MAC addresses. It does not change assignment based on DUID.
|
|
---
|
|
src/rfc3315.c | 55 +++++++++++++++++++++++++++++++++++++++++++--------
|
|
1 file changed, 47 insertions(+), 8 deletions(-)
|
|
|
|
--- a/src/rfc3315.c
|
|
+++ b/src/rfc3315.c
|
|
@@ -48,7 +48,7 @@ static int build_ia(struct state *state,
|
|
static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
|
|
static void mark_context_used(struct state *state, struct in6_addr *addr);
|
|
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
|
|
-static int check_address(struct state *state, struct in6_addr *addr);
|
|
+static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr);
|
|
static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
|
|
static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
|
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
|
|
@@ -688,8 +688,13 @@ static int dhcp6_no_relay(struct state *
|
|
}
|
|
else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
|
|
continue; /* not an address we're allowed */
|
|
- else if (!check_address(state, &req_addr))
|
|
+ else if (!check_address(state, config, &req_addr))
|
|
continue; /* address leased elsewhere */
|
|
+ else if (state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
|
|
+ match_netid(c->filter, solicit_tags, plain_range) &&
|
|
+ !config_implies(config, c, &req_addr))
|
|
+ continue; /* another static address is configured */
|
|
|
|
/* add address to output packet */
|
|
add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
|
|
@@ -701,7 +706,10 @@ static int dhcp6_no_relay(struct state *
|
|
|
|
/* Suggest configured address(es) */
|
|
for (c = state->context; c; c = c->current)
|
|
- if (!(c->flags & CONTEXT_CONF_USED) &&
|
|
+ if ((!(c->flags & CONTEXT_CONF_USED) ||
|
|
+ (state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type)
|
|
+ )) &&
|
|
match_netid(c->filter, solicit_tags, plain_range) &&
|
|
config_valid(config, c, &addr, state, now))
|
|
{
|
|
@@ -725,6 +733,11 @@ static int dhcp6_no_relay(struct state *
|
|
req_addr = ltmp->addr6;
|
|
if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
|
|
{
|
|
+ if (state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
|
|
+ match_netid(c->filter, solicit_tags, plain_range) &&
|
|
+ !config_implies(config, c, &req_addr))
|
|
+ continue; /* skip this lease because another static address is configured */
|
|
add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
|
|
mark_context_used(state, &req_addr);
|
|
get_context_tag(state, c);
|
|
@@ -859,7 +872,7 @@ static int dhcp6_no_relay(struct state *
|
|
put_opt6_string(_("address unavailable"));
|
|
end_opt6(o1);
|
|
}
|
|
- else if (!check_address(state, &req_addr))
|
|
+ else if (!check_address(state, config, &req_addr))
|
|
{
|
|
/* Address leased to another DUID/IAID */
|
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
|
@@ -989,6 +1002,16 @@ static int dhcp6_no_relay(struct state *
|
|
{
|
|
unsigned int lease_time;
|
|
|
|
+ /* check if another static address is preferred */
|
|
+ if (state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
|
|
+ !config_implies(config, this_context, &req_addr))
|
|
+ {
|
|
+ preferred_time = valid_time = 0;
|
|
+ message = _("deprecated");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
get_context_tag(state, this_context);
|
|
|
|
if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME))
|
|
@@ -1014,6 +1037,7 @@ static int dhcp6_no_relay(struct state *
|
|
|
|
if (preferred_time == 0)
|
|
message = _("deprecated");
|
|
+ }
|
|
|
|
address_assigned = 1;
|
|
}
|
|
@@ -1070,11 +1094,22 @@ static int dhcp6_no_relay(struct state *
|
|
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
|
{
|
|
struct in6_addr req_addr;
|
|
+ struct dhcp_context *c;
|
|
+ int config_addr_ok = 1;
|
|
|
|
/* alignment */
|
|
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
|
+
|
|
+ c = address6_valid(state->context, &req_addr, tagif, 1);
|
|
+
|
|
+ if (c && state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type) &&
|
|
+ !config_implies(config, c, &req_addr))
|
|
+ {
|
|
+ config_addr_ok = 0;
|
|
+ }
|
|
|
|
- if (!address6_valid(state->context, &req_addr, tagif, 1))
|
|
+ if (!c || !config_addr_ok)
|
|
{
|
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
|
put_opt6_short(DHCP6NOTONLINK);
|
|
@@ -1692,11 +1727,15 @@ static void mark_config_used(struct dhcp
|
|
context->flags |= CONTEXT_CONF_USED;
|
|
}
|
|
|
|
-/* make sure address not leased to another CLID/IAID */
|
|
-static int check_address(struct state *state, struct in6_addr *addr)
|
|
+/* check that ipv6 address belongs to config with same mac address as in state or ipv6 address is not leased to another CLID/IAID */
|
|
+static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr)
|
|
{
|
|
struct dhcp_lease *lease;
|
|
|
|
+ if (state->mac_len && config &&
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type))
|
|
+ return 1;
|
|
+
|
|
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
|
|
return 1;
|
|
|
|
@@ -1773,7 +1812,7 @@ static int config_valid(struct dhcp_conf
|
|
{
|
|
setaddr6part(addr, addrpart+i);
|
|
|
|
- if (check_address(state, addr))
|
|
+ if (check_address(state, config, addr))
|
|
return 1;
|
|
}
|
|
}
|