236 lines
9.7 KiB
Diff
236 lines
9.7 KiB
Diff
|
|
From 271510e5f7c2130ad4b7e33186e47daf0d3d2d30 Mon Sep 17 00:00:00 2001
|
||
|
|
From: huyizhen <huyizhen2@huawei.com>
|
||
|
|
Date: Fri, 28 Feb 2025 14:38:44 +0800
|
||
|
|
Subject: [PATCH] allow binding mac with ip6
|
||
|
|
|
||
|
|
Bind the IPv6 address to the MAC address of the client.
|
||
|
|
This command is used to solve the problem that the client cannot obtain an IPv6 address
|
||
|
|
after the system is reinstalled. If this parameter is not specified, the client duid changes
|
||
|
|
and cannot obtain the original IPv6 address. After this parameter is added, even if the DUID
|
||
|
|
of the client changes, the client can still obtain the bound IPv6 address.
|
||
|
|
Description:
|
||
|
|
This feature conflicts with the RFC 3315 standard and applies only to private networks.
|
||
|
|
In addition, all client MAC addresses and IPv6 addresses must be bound in one-to-one mode
|
||
|
|
using --dhcp-host.
|
||
|
|
Combine bugfix-allow-binding-mac-with-ipv6.patch
|
||
|
|
bugfix-deal-with-CONFRIM-when-binding-mac-with-ipv6.patch
|
||
|
|
to allow-binding-mac-with-ip6.patch
|
||
|
|
---
|
||
|
|
src/dnsmasq.c | 1 +
|
||
|
|
src/dnsmasq.h | 4 +++-
|
||
|
|
src/option.c | 3 +++
|
||
|
|
src/rfc3315.c | 61 ++++++++++++++++++++++++++++++++++++++++++---------
|
||
|
|
4 files changed, 58 insertions(+), 11 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
|
||
|
|
index f3d87cd..3609106 100644
|
||
|
|
--- a/src/dnsmasq.c
|
||
|
|
+++ b/src/dnsmasq.c
|
||
|
|
@@ -281,6 +281,7 @@ int main (int argc, char **argv)
|
||
|
|
{
|
||
|
|
daemon->doing_ra = option_bool(OPT_RA);
|
||
|
|
|
||
|
|
+ daemon->bind_mac_with_ip6 = option_bool(OPT_BIND_MAC_IP6);
|
||
|
|
for (context = daemon->dhcp6; context; context = context->next)
|
||
|
|
{
|
||
|
|
if (context->flags & CONTEXT_DHCP)
|
||
|
|
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||
|
|
index e455c3f..ef32f06 100644
|
||
|
|
--- a/src/dnsmasq.h
|
||
|
|
+++ b/src/dnsmasq.h
|
||
|
|
@@ -282,7 +282,8 @@ struct event_desc {
|
||
|
|
#define OPT_NO_IDENT 70
|
||
|
|
#define OPT_CACHE_RR 71
|
||
|
|
#define OPT_LOCALHOST_SERVICE 72
|
||
|
|
-#define OPT_LAST 73
|
||
|
|
+#define OPT_BIND_MAC_IP6 73
|
||
|
|
+#define OPT_LAST 74
|
||
|
|
|
||
|
|
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||
|
|
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||
|
|
@@ -1211,6 +1212,7 @@ extern struct daemon {
|
||
|
|
int override;
|
||
|
|
int enable_pxe;
|
||
|
|
int doing_ra, doing_dhcp6;
|
||
|
|
+ int bind_mac_with_ip6;
|
||
|
|
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||
|
|
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||
|
|
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||
|
|
diff --git a/src/option.c b/src/option.c
|
||
|
|
index 9b5066e..7c316b9 100644
|
||
|
|
--- a/src/option.c
|
||
|
|
+++ b/src/option.c
|
||
|
|
@@ -192,6 +192,7 @@ struct myoption {
|
||
|
|
#define LOPT_NO_DHCP4 383
|
||
|
|
#define LOPT_MAX_PROCS 384
|
||
|
|
#define LOPT_DNSSEC_LIMITS 385
|
||
|
|
+#define LOPT_BIND_MAC_IP6 386
|
||
|
|
|
||
|
|
#ifdef HAVE_GETOPT_LONG
|
||
|
|
static const struct option opts[] =
|
||
|
|
@@ -388,6 +389,7 @@ static const struct myoption opts[] =
|
||
|
|
{ "use-stale-cache", 2, 0 , LOPT_STALE_CACHE },
|
||
|
|
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
||
|
|
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
||
|
|
+ { "bind-mac-with-ip6", 0, 0 , LOPT_BIND_MAC_IP6 },
|
||
|
|
{ NULL, 0, 0, 0 }
|
||
|
|
};
|
||
|
|
|
||
|
|
@@ -591,6 +593,7 @@ static struct {
|
||
|
|
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
||
|
|
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
||
|
|
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
||
|
|
+ { LOPT_BIND_MAC_IP6, OPT_BIND_MAC_IP6, NULL, gettext_noop("Bind mac with ipv6 address. This is an experimental feature and it conflicts with rfc3315."), NULL },
|
||
|
|
{ 0, 0, NULL, NULL, NULL }
|
||
|
|
};
|
||
|
|
|
||
|
|
diff --git a/src/rfc3315.c b/src/rfc3315.c
|
||
|
|
index 400d939..e579494 100644
|
||
|
|
--- a/src/rfc3315.c
|
||
|
|
+++ b/src/rfc3315.c
|
||
|
|
@@ -48,8 +48,8 @@ static int build_ia(struct state *state, int *t1cntr);
|
||
|
|
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 config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
|
||
|
|
+static int check_address(struct dhcp_config *config, struct state *state, struct in6_addr *addr, time_t now, int preempte);
|
||
|
|
+static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now, int preempte);
|
||
|
|
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,
|
||
|
|
unsigned int *min_time, struct in6_addr *addr, time_t now);
|
||
|
|
@@ -699,7 +699,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
/* 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, state, now))
|
||
|
|
+ if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state, now, 0))
|
||
|
|
{
|
||
|
|
req_addr = addr;
|
||
|
|
mark_config_used(c, &addr);
|
||
|
|
@@ -708,7 +708,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
}
|
||
|
|
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(config, state, &req_addr, now, 0))
|
||
|
|
continue; /* address leased elsewhere */
|
||
|
|
|
||
|
|
/* add address to output packet */
|
||
|
|
@@ -723,7 +723,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
for (c = state->context; c; c = c->current)
|
||
|
|
if (!(c->flags & CONTEXT_CONF_USED) &&
|
||
|
|
match_netid(c->filter, solicit_tags, plain_range) &&
|
||
|
|
- config_valid(config, c, &addr, state, now))
|
||
|
|
+ config_valid(config, c, &addr, state, now, 1))
|
||
|
|
{
|
||
|
|
mark_config_used(state->context, &addr);
|
||
|
|
if (have_config(config, CONFIG_TIME))
|
||
|
|
@@ -879,7 +879,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
put_opt6_string(_("address unavailable"));
|
||
|
|
end_opt6(o1);
|
||
|
|
}
|
||
|
|
- else if (!check_address(state, &req_addr))
|
||
|
|
+ else if (!check_address(config, state, &req_addr, now, 0))
|
||
|
|
{
|
||
|
|
/* Address leased to another DUID/IAID */
|
||
|
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||
|
|
@@ -1075,12 +1075,32 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
case DHCP6CONFIRM:
|
||
|
|
{
|
||
|
|
int good_addr = 0, bad_addr = 0;
|
||
|
|
+ int find_bind = 0;
|
||
|
|
+ struct dhcp_config *find_config = NULL;
|
||
|
|
|
||
|
|
/* set reply message type */
|
||
|
|
outmsgtype = DHCP6REPLY;
|
||
|
|
|
||
|
|
log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
|
||
|
|
-
|
||
|
|
+
|
||
|
|
+ if(daemon->bind_mac_with_ip6) {
|
||
|
|
+ if(state->mac) {
|
||
|
|
+ for (find_config = daemon->dhcp_conf; find_config; find_config = find_config->next)
|
||
|
|
+ if (config_has_mac(find_config, state->mac, state->mac_len, state->mac_type) && have_config(find_config, CONFIG_ADDR6)) {
|
||
|
|
+ find_bind = 1;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ /* requires all mac has binding ipv6 address. */
|
||
|
|
+ if (find_bind == 0) {
|
||
|
|
+ o1 = new_opt6(OPTION6_STATUS_CODE);
|
||
|
|
+ put_opt6_short(DHCP6NOTONLINK);
|
||
|
|
+ put_opt6_string(_("confirm failed, no binding found"));
|
||
|
|
+ end_opt6(o1);
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||
|
|
{
|
||
|
|
void *ia_option, *ia_end;
|
||
|
|
@@ -1104,6 +1124,16 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
|
||
|
|
good_addr = 1;
|
||
|
|
log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ if(daemon->bind_mac_with_ip6) {
|
||
|
|
+ if (!is_same_net6(&req_addr, &find_config->addr6, 128)) {
|
||
|
|
+ o1 = new_opt6(OPTION6_STATUS_CODE);
|
||
|
|
+ put_opt6_short(DHCP6NOTONLINK);
|
||
|
|
+ put_opt6_string(_("confirm failed, not binding to this address"));
|
||
|
|
+ end_opt6(o1);
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1723,13 +1753,24 @@ static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr
|
||
|
|
}
|
||
|
|
|
||
|
|
/* make sure address not leased to another CLID/IAID */
|
||
|
|
-static int check_address(struct state *state, struct in6_addr *addr)
|
||
|
|
+static int check_address(struct dhcp_config *config, struct state *state, struct in6_addr *addr, time_t now, int preempte)
|
||
|
|
{
|
||
|
|
struct dhcp_lease *lease;
|
||
|
|
|
||
|
|
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
+ if (preempte && daemon->bind_mac_with_ip6) {
|
||
|
|
+ // break rfc3315 here
|
||
|
|
+ // bind mac address with a lease
|
||
|
|
+ if ((state->mac) && !(config->flags & CONFIG_CLID) &&
|
||
|
|
+ config_has_mac(config, state->mac, state->mac_len, state->mac_type)) {
|
||
|
|
+ lease_prune(lease, now);
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // what rfc3315 do
|
||
|
|
if (lease->clid_len != state->clid_len ||
|
||
|
|
memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
|
||
|
|
lease->iaid != state->iaid)
|
||
|
|
@@ -1769,7 +1810,7 @@ static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_c
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
-static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now)
|
||
|
|
+static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now, int preempte)
|
||
|
|
{
|
||
|
|
u64 addrpart, i, addresses;
|
||
|
|
struct addrlist *addr_list;
|
||
|
|
@@ -1803,7 +1844,7 @@ static int config_valid(struct dhcp_config *config, struct dhcp_context *context
|
||
|
|
{
|
||
|
|
setaddr6part(addr, addrpart+i);
|
||
|
|
|
||
|
|
- if (check_address(state, addr))
|
||
|
|
+ if (check_address(config, state, addr, now, preempte))
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|