[Dnsmasq-discuss] [PATCH] DHCPv6: Honor assigning IPv6 address based on MAC address
Geert Stappers
stappers at hendrikx-itc.nl
Tue Feb 12 12:41:43 GMT 2019
Another request for
Hey, could this patch get reviewed?
On 06-02-2019 21:29, Pali Rohár wrote:
> PING
>
> On Friday 11 January 2019 17:52:43 Pali Rohár wrote:
>> Hello, can somebody look at this patch?
>>
>> I remember that more people asked for ability to assign IPv6 address
>> based on MAC address specified in config file, rather then IAID/DUID.
>>
>> On Monday 17 December 2018 18:41:09 Pali Rohár wrote:
>>> 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.
>>>
>>> Also this patch adds support for allowing IPv6 address to be associated
>>> with multiple hardware addresses, and gives dnsmasq permission to abandon a
>>> lease. This is similar functionality as already supported for IPv4 address.
>>> ---
>>> man/dnsmasq.8 | 9 ++++++---
>>> src/rfc3315.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
>>> 2 files changed, 59 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
>>> index f01a5ba..8614f08 100644
>>> --- a/man/dnsmasq.8
>>> +++ b/man/dnsmasq.8
>>> @@ -1068,10 +1068,13 @@ will only match a
>>> Token-Ring hardware address, since the ARP-address type for token ring
>>> is 6.
>>>
>>> -As a special case, in DHCPv4, it is possible to include more than one
>>> -hardware address. eg:
>>> +It is possible to include more than one hardware address. eg for IPv4:
>>> .B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
>>> -This allows an IP address to be associated with
>>> +or for IPv6:
>>> +.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,[::2]
>>> +or for both:
>>> +.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2,[::2]
>>> +This allows an IPv4 and/or IPv6 address to be associated with
>>> multiple hardware addresses, and gives dnsmasq permission to abandon a
>>> DHCP lease to one of the hardware addresses when another one asks for
>>> a lease. Beware that this is a dangerous thing to do, it will only
>>> diff --git a/src/rfc3315.c b/src/rfc3315.c
>>> index a20776d..c83cf2d 100644
>>> --- a/src/rfc3315.c
>>> +++ b/src/rfc3315.c
>>> @@ -54,7 +54,7 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
>>> #endif
>>> 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 void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
>>> unsigned int *min_time, struct in6_addr *addr, time_t now);
>>> static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
>>> @@ -746,7 +746,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> /* If the client asks for an address on the same network as a configured address,
>>> offer the configured address instead, to make moving to newly-configured
>>> addresses automatic. */
>>> - if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
>>> + if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, config, &addr))
>>> {
>>> req_addr = addr;
>>> mark_config_used(c, &addr);
>>> @@ -755,8 +755,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> }
>>> 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_valid(config, c, &addr) &&
>>> + !IN6_ARE_ADDR_EQUAL(&req_addr, &addr))
>>> + continue; /* another static address is configured */
>>>
>>> /* add address to output packet */
>>> #ifdef OPTION6_PREFIX_CLASS
>>> @@ -772,10 +778,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>>
>>> /* 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) &&
>>> - check_address(state, &addr))
>>> + check_address(state, config, &addr))
>>> {
>>> mark_config_used(state->context, &addr);
>>> if (have_config(config, CONFIG_TIME))
>>> @@ -800,6 +809,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> 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_valid(config, c, &addr) &&
>>> + !IN6_ARE_ADDR_EQUAL(&req_addr, &addr))
>>> + continue; /* skip this lease because another static address is configured */
>>> #ifdef OPTION6_PREFIX_CLASS
>>> if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
>>> state->send_prefix_class = prefix_class_from_context(c);
>>> @@ -943,7 +958,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> 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);
>>> @@ -1064,6 +1079,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> struct in6_addr addr;
>>> 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_valid(config, this_context, &addr) &&
>>> + !IN6_ARE_ADDR_EQUAL(&req_addr, &addr))
>>> + {
>>> + preferred_time = valid_time = 0;
>>> + message = _("deprecated");
>>> + }
>>> + else
>>> + {
>>> get_context_tag(state, this_context);
>>>
>>> if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
>>> @@ -1089,6 +1115,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>>
>>> if (preferred_time == 0)
>>> message = _("deprecated");
>>> + }
>>> }
>>> else
>>> {
>>> @@ -1135,11 +1162,24 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
>>> ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
>>> {
>>> struct in6_addr req_addr;
>>> + struct in6_addr 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_valid(config, c, &addr) &&
>>> + !IN6_ARE_ADDR_EQUAL(&req_addr, &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);
>>> @@ -1772,11 +1812,15 @@ static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr
>>> 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;
>>>
>
> _______________________________________________
> Dnsmasq-discuss mailing list
> Dnsmasq-discuss at lists.thekelleys.org.uk
> http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/attachments/20190212/3b8fa057/attachment.html>
More information about the Dnsmasq-discuss
mailing list