|
| 1 | +From 93ac8f9d469ff08d41170eb6934842b3626d5fdd Mon Sep 17 00:00:00 2001 |
| 2 | +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= < [email protected]> |
| 3 | +Date: Wed, 23 Dec 2015 22:10:44 +0100 |
| 4 | +Subject: [PATCH] DHCPv6: Honor assigning IPv6 address based on MAC address |
| 5 | + |
| 6 | +Currently IPv6 addresses are assigned to tuple (IAID, DUID). When system |
| 7 | +changes IAID/DUID then old assigned IPv6 address cannot be reused, even |
| 8 | +when in config file was DHCPv6 assignment based on MAC address (and not on |
| 9 | +DUID). |
| 10 | + |
| 11 | +IAID/DUID is changed when rebooting from one operating system to another; |
| 12 | +or after reinstalling system. In reality it is normal that DUID of some |
| 13 | +machine is changed, so people rather assign also IPv6 addresses based on |
| 14 | +MAC address. |
| 15 | + |
| 16 | +So assigning IPv6 based on MAC address in dnsmasq is currently semi-broken. |
| 17 | + |
| 18 | +This patch tries to fix it and honors IPv6 config rules with MAC address, |
| 19 | +to always assign particular IPv6 address to specific MAC address (when |
| 20 | +configured). And ignores the fact if IAID/DUID was changed. |
| 21 | + |
| 22 | +Normally IPv6 address should be assigned by IAID/DUID (which also state |
| 23 | +DHCPv6 RFCs), but dnsmasq has already some support for assigning IPv6 |
| 24 | +address based on MAC address, when users configured in config file. |
| 25 | + |
| 26 | +So this patch just tries to fix above problem for user configuration with |
| 27 | +MAC addresses. It does not change assignment based on DUID. |
| 28 | +--- |
| 29 | + src/rfc3315.c | 55 +++++++++++++++++++++++++++++++++++++++++++-------- |
| 30 | + 1 file changed, 47 insertions(+), 8 deletions(-) |
| 31 | + |
| 32 | +--- a/src/rfc3315.c |
| 33 | ++++ b/src/rfc3315.c |
| 34 | +@@ -48,7 +48,7 @@ static int build_ia(struct state *state, |
| 35 | + static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz); |
| 36 | + static void mark_context_used(struct state *state, struct in6_addr *addr); |
| 37 | + static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr); |
| 38 | +-static int check_address(struct state *state, struct in6_addr *addr); |
| 39 | ++static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr); |
| 40 | + static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now); |
| 41 | + static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr); |
| 42 | + static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, |
| 43 | +@@ -688,8 +688,13 @@ static int dhcp6_no_relay(struct state * |
| 44 | + } |
| 45 | + else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range))) |
| 46 | + continue; /* not an address we're allowed */ |
| 47 | +- else if (!check_address(state, &req_addr)) |
| 48 | ++ else if (!check_address(state, config, &req_addr)) |
| 49 | + continue; /* address leased elsewhere */ |
| 50 | ++ else if (state->mac_len && config && |
| 51 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type) && |
| 52 | ++ match_netid(c->filter, solicit_tags, plain_range) && |
| 53 | ++ !config_implies(config, c, &req_addr)) |
| 54 | ++ continue; /* another static address is configured */ |
| 55 | + |
| 56 | + /* add address to output packet */ |
| 57 | + add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now); |
| 58 | +@@ -701,7 +706,10 @@ static int dhcp6_no_relay(struct state * |
| 59 | + |
| 60 | + /* Suggest configured address(es) */ |
| 61 | + for (c = state->context; c; c = c->current) |
| 62 | +- if (!(c->flags & CONTEXT_CONF_USED) && |
| 63 | ++ if ((!(c->flags & CONTEXT_CONF_USED) || |
| 64 | ++ (state->mac_len && config && |
| 65 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type) |
| 66 | ++ )) && |
| 67 | + match_netid(c->filter, solicit_tags, plain_range) && |
| 68 | + config_valid(config, c, &addr, state, now)) |
| 69 | + { |
| 70 | +@@ -725,6 +733,11 @@ static int dhcp6_no_relay(struct state * |
| 71 | + req_addr = ltmp->addr6; |
| 72 | + if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range))) |
| 73 | + { |
| 74 | ++ if (state->mac_len && config && |
| 75 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type) && |
| 76 | ++ match_netid(c->filter, solicit_tags, plain_range) && |
| 77 | ++ !config_implies(config, c, &req_addr)) |
| 78 | ++ continue; /* skip this lease because another static address is configured */ |
| 79 | + add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now); |
| 80 | + mark_context_used(state, &req_addr); |
| 81 | + get_context_tag(state, c); |
| 82 | +@@ -859,7 +872,7 @@ static int dhcp6_no_relay(struct state * |
| 83 | + put_opt6_string(_("address unavailable")); |
| 84 | + end_opt6(o1); |
| 85 | + } |
| 86 | +- else if (!check_address(state, &req_addr)) |
| 87 | ++ else if (!check_address(state, config, &req_addr)) |
| 88 | + { |
| 89 | + /* Address leased to another DUID/IAID */ |
| 90 | + o1 = new_opt6(OPTION6_STATUS_CODE); |
| 91 | +@@ -989,6 +1002,16 @@ static int dhcp6_no_relay(struct state * |
| 92 | + { |
| 93 | + unsigned int lease_time; |
| 94 | + |
| 95 | ++ /* check if another static address is preferred */ |
| 96 | ++ if (state->mac_len && config && |
| 97 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type) && |
| 98 | ++ !config_implies(config, this_context, &req_addr)) |
| 99 | ++ { |
| 100 | ++ preferred_time = valid_time = 0; |
| 101 | ++ message = _("deprecated"); |
| 102 | ++ } |
| 103 | ++ else |
| 104 | ++ { |
| 105 | + get_context_tag(state, this_context); |
| 106 | + |
| 107 | + if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME)) |
| 108 | +@@ -1014,6 +1037,7 @@ static int dhcp6_no_relay(struct state * |
| 109 | + |
| 110 | + if (preferred_time == 0) |
| 111 | + message = _("deprecated"); |
| 112 | ++ } |
| 113 | + |
| 114 | + address_assigned = 1; |
| 115 | + } |
| 116 | +@@ -1070,11 +1094,22 @@ static int dhcp6_no_relay(struct state * |
| 117 | + ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) |
| 118 | + { |
| 119 | + struct in6_addr req_addr; |
| 120 | ++ struct dhcp_context *c; |
| 121 | ++ int config_addr_ok = 1; |
| 122 | + |
| 123 | + /* alignment */ |
| 124 | + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); |
| 125 | ++ |
| 126 | ++ c = address6_valid(state->context, &req_addr, tagif, 1); |
| 127 | ++ |
| 128 | ++ if (c && state->mac_len && config && |
| 129 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type) && |
| 130 | ++ !config_implies(config, c, &req_addr)) |
| 131 | ++ { |
| 132 | ++ config_addr_ok = 0; |
| 133 | ++ } |
| 134 | + |
| 135 | +- if (!address6_valid(state->context, &req_addr, tagif, 1)) |
| 136 | ++ if (!c || !config_addr_ok) |
| 137 | + { |
| 138 | + o1 = new_opt6(OPTION6_STATUS_CODE); |
| 139 | + put_opt6_short(DHCP6NOTONLINK); |
| 140 | +@@ -1692,11 +1727,15 @@ static void mark_config_used(struct dhcp |
| 141 | + context->flags |= CONTEXT_CONF_USED; |
| 142 | + } |
| 143 | + |
| 144 | +-/* make sure address not leased to another CLID/IAID */ |
| 145 | +-static int check_address(struct state *state, struct in6_addr *addr) |
| 146 | ++/* check that ipv6 address belongs to config with same mac address as in state or ipv6 address is not leased to another CLID/IAID */ |
| 147 | ++static int check_address(struct state *state, struct dhcp_config *config, struct in6_addr *addr) |
| 148 | + { |
| 149 | + struct dhcp_lease *lease; |
| 150 | + |
| 151 | ++ if (state->mac_len && config && |
| 152 | ++ config_has_mac(config, state->mac, state->mac_len, state->mac_type)) |
| 153 | ++ return 1; |
| 154 | ++ |
| 155 | + if (!(lease = lease6_find_by_addr(addr, 128, 0))) |
| 156 | + return 1; |
| 157 | + |
| 158 | +@@ -1773,7 +1812,7 @@ static int config_valid(struct dhcp_conf |
| 159 | + { |
| 160 | + setaddr6part(addr, addrpart+i); |
| 161 | + |
| 162 | +- if (check_address(state, addr)) |
| 163 | ++ if (check_address(state, config, addr)) |
| 164 | + return 1; |
| 165 | + } |
| 166 | + } |
0 commit comments