[Dnsmasq-discuss] [PATCH] dhcp-host - tag filtering
Harald Jensås
hjensas at redhat.com
Fri Jan 31 18:56:18 GMT 2020
>From a2a022cd3adc6c0ad6007c63bba3fd4a2ff28165 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Harald=20Jens=C3=A5s?= <hjensas at redhat.com>
Date: Fri, 31 Jan 2020 18:10:08 +0100
Subject: [PATCH] dhcp-host - tag filtering
Adds support for tag's on the dhcp-host config entries.
Find config will collect candidate configurations based
on clid and hwadd in a list. A candidate is then picked
by iterating the list, candidates with matching tag's
are preferred. If no entry with tag's is a match and
an entry without tags exist this will be used.
NOTE: For dhcp-host entries with a wildcard hardware
address tags are ignored.
---
src/dhcp-common.c | 68 ++++++++++++++++++++++++++++++++++++++++-------
src/dnsmasq.h | 9 ++++++-
src/lease.c | 2 +-
src/option.c | 9 ++++---
src/rfc2131.c | 6 ++---
src/rfc3315.c | 6 ++---
6 files changed, 80 insertions(+), 20 deletions(-)
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index dc7f945..4d5e67d 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -295,15 +295,28 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
return 0;
}
+static void dhcp_config_list_free(struct dhcp_config_list *config_list)
+{
+ while (config_list)
+ {
+ struct dhcp_config_list *tmplist = config_list;
+ config_list = config_list->next;
+ free(tmplist);
+ }
+}
+
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
- int hw_type, char *hostname)
+ int hw_type, char *hostname,
+ struct dhcp_netid *tags)
{
int count, new;
- struct dhcp_config *config, *candidate;
+ struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
+ struct dhcp_config_list *config_candidates;
+ config_candidates = NULL;
if (clid)
for (config = configs; config; config = config->next)
@@ -312,7 +325,13 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_config_in_context(context, config))
- return config;
+ {
+ struct dhcp_config_list *newlist = safe_malloc(sizeof(struct dhcp_config));
+ newlist->next = config_candidates;
+ config_candidates = newlist;
+ newlist->config = config;
+ continue;
+ }
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here. This is IPv4 only. context==NULL implies IPv4,
@@ -320,24 +339,55 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_config_in_context(context, config))
- return config;
+ {
+ struct dhcp_config_list *newlist = safe_malloc(sizeof(struct dhcp_config_list));
+ newlist->next = config_candidates;
+ config_candidates = newlist;
+ newlist->config = config;
+ }
}
-
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_config_in_context(context, config))
- return config;
+ {
+ struct dhcp_config_list *newlist = safe_malloc(sizeof(struct dhcp_config_list));
+ newlist->next = config_candidates;
+ config_candidates = newlist;
+ newlist->config = config;
+ }
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context(context, config))
- return config;
+ {
+ struct dhcp_config_list *newlist = safe_malloc(sizeof(struct dhcp_config_list));
+ newlist->next = config_candidates;
+ config_candidates = newlist;
+ newlist->config = config;
+ }
+
+ if (config_candidates)
+ {
+ for (candidate = NULL, config_candidates = config_candidates;
+ config_candidates; config_candidates = config_candidates->next)
+ if (!candidate && (config_candidates->config->filter == NULL))
+ candidate = config_candidates->config;
+ else if (config_candidates->config->filter != NULL)
+ if (match_netid(config_candidates->config->filter, tags, 0))
+ {
+ candidate = config_candidates->config;
+ break;
+ }
+
+ dhcp_config_list_free(config_candidates);
+ if (candidate)
+ return candidate;
+ }
-
if (!hwaddr)
return NULL;
@@ -353,7 +403,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
count = new;
candidate = config;
}
-
+
return candidate;
}
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 7fb440c..072bbfd 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -759,12 +759,18 @@ struct hwaddr_config {
struct hwaddr_config *next;
};
+struct dhcp_config_list {
+ struct dhcp_config *config;
+ struct dhcp_config_list *next;
+};
+
struct dhcp_config {
unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
char *hostname, *domain;
struct dhcp_netid_list *netid;
+ struct dhcp_netid *filter;
#ifdef HAVE_DHCP6
struct in6_addr addr6;
#endif
@@ -1555,7 +1561,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
- int hw_type, char *hostname);
+ int hw_type, char *hostname,
+ struct dhcp_netid *tags);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);
diff --git a/src/lease.c b/src/lease.c
index 0035d40..52cf30a 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -230,7 +230,7 @@ void lease_update_from_configs(void)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
- lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
+ lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
diff --git a/src/option.c b/src/option.c
index f77545f..a7a175b 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1027,6 +1027,7 @@ static void dhcp_config_free(struct dhcp_config *config)
free(tmp);
}
dhcp_netid_list_free(config->netid);
+ dhcp_netid_free(config->filter);
if (config->flags & CONFIG_CLID)
free(config->clid);
free(config);
@@ -3204,6 +3205,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL;
new->netid = NULL;
+ new->filter = NULL;
new->clid = NULL;
if ((a[0] = arg))
@@ -3257,9 +3259,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
else if (strstr(arg, "tag:") == arg)
{
-
- dhcp_config_free(new);
- ret_err(_("cannot match tags in --dhcp-host"));
+ struct dhcp_netid *newlist = opt_malloc(sizeof(struct dhcp_netid));
+ newlist->next = new->filter;
+ new->filter = newlist;
+ newlist->net = arg+4;
}
#ifdef HAVE_DHCP6
else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 55fedcc..26223fc 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -504,7 +504,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->op = BOOTREPLY;
config = find_config(daemon->dhcp_conf, context, clid, clid_len,
- mess->chaddr, mess->hlen, mess->htype, NULL);
+ mess->chaddr, mess->hlen, mess->htype, NULL, netid);
/* set "known" tag for known hosts */
if (config)
@@ -514,7 +514,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &known_id;
}
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len,
- mess->chaddr, mess->hlen, mess->htype, NULL))
+ mess->chaddr, mess->hlen, mess->htype, NULL, netid))
{
known_id.net = "known-othernet";
known_id.next = netid;
@@ -781,7 +781,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
to avoid impersonation by name. */
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
mess->chaddr, mess->hlen,
- mess->htype, hostname);
+ mess->htype, hostname, netid);
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{
config = new;
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 9471f5c..9fb1201 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -524,7 +524,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
if (state->clid &&
- (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL)) &&
+ (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL, state->tags)) &&
have_config(config, CONFIG_NAME))
{
state->hostname = config->hostname;
@@ -544,7 +544,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* Search again now we have a hostname.
Only accept configs without CLID here, (it won't match)
to avoid impersonation by name. */
- struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
+ struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, state->tags);
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
config = new;
}
@@ -570,7 +570,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ignore = 1;
}
else if (state->clid &&
- find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
+ find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL, state->tags))
{
known_id.net = "known-othernet";
known_id.next = state->tags;
--
2.24.1
More information about the Dnsmasq-discuss
mailing list