Add tag filtering of dhcp-host directives.

This commit is contained in:
Simon Kelley
2020-02-07 21:05:54 +00:00
parent 137286e9ba
commit 52ec783613
8 changed files with 58 additions and 28 deletions

View File

@@ -78,6 +78,9 @@ version 2.81
boot. Many thanks to Harald Jensås for his work on this idea and boot. Many thanks to Harald Jensås for his work on this idea and
earlier patches. earlier patches.
Add filtering by tag of --dhcp-host directives. Based on a patch
by Harald Jensås.
version 2.80 version 2.80
Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method

View File

@@ -975,7 +975,7 @@ is also included, as described in RFC-3775 section 7.3.
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set. tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
.TP .TP
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore] .B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine Specify per host parameters for the DHCP server. This allows a machine
with a particular hardware address to be always allocated the same with a particular hardware address to be always allocated the same
hostname, IP address and lease time. A hostname specified like this hostname, IP address and lease time. A hostname specified like this
@@ -1060,6 +1060,9 @@ ignore requests from unknown machines using
.B --dhcp-ignore=tag:!known .B --dhcp-ignore=tag:!known
If the host matches only a \fB--dhcp-host\fP directive which cannot If the host matches only a \fB--dhcp-host\fP directive which cannot
be used because it specifies an address on different subnet, the tag "known-othernet" is set. be used because it specifies an address on different subnet, the tag "known-othernet" is set.
The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
Ethernet addresses (but not client-ids) may have Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore .B --dhcp-host=00:20:e0:3b:13:*,ignore

View File

@@ -304,11 +304,12 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
return 0; return 0;
} }
struct dhcp_config *find_config(struct dhcp_config *configs, static struct dhcp_config *find_config_match(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *clid, int clid_len, unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len, unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname) int hw_type, char *hostname,
struct dhcp_netid *tags, int tag_not_needed)
{ {
int count, new; int count, new;
struct dhcp_config *config, *candidate; struct dhcp_config *config, *candidate;
@@ -320,7 +321,9 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
{ {
if (config->clid_len == clid_len && if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 && memcmp(config->clid, clid, clid_len) == 0 &&
is_config_in_context(context, config)) is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config; return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
@@ -328,7 +331,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
see lease_update_from_configs() */ see lease_update_from_configs() */
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 && if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 && memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_config_in_context(context, config)) is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config; return config;
} }
@@ -336,14 +340,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
if (hwaddr) if (hwaddr)
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) && if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_config_in_context(context, config)) is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config; return config;
if (hostname && context) if (hostname && context)
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) && if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) && hostname_isequal(config->hostname, hostname) &&
is_config_in_context(context, config)) is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config; return config;
@@ -352,7 +358,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
/* use match with fewest wildcard octets */ /* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next) for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_config_in_context(context, config)) if (is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 && if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len && conf_addr->hwaddr_len == hw_len &&
@@ -366,6 +373,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return candidate; return candidate;
} }
/* Find tagged configs first. */
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, struct dhcp_netid *tags)
{
struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
if (!ret)
ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
return ret;
}
void dhcp_update_configs(struct dhcp_config *configs) void dhcp_update_configs(struct dhcp_config *configs)
{ {
/* Some people like to keep all static IP addresses in /etc/hosts. /* Some people like to keep all static IP addresses in /etc/hosts.

View File

@@ -767,6 +767,7 @@ struct dhcp_config {
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
char *hostname, *domain; char *hostname, *domain;
struct dhcp_netid_list *netid; struct dhcp_netid_list *netid;
struct dhcp_netid *filter;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
struct addrlist *addr6; struct addrlist *addr6;
#endif #endif
@@ -1555,7 +1556,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *clid, int clid_len, unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len, unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname); int hw_type, char *hostname,
struct dhcp_netid *filter);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
char *whichdevice(void); char *whichdevice(void);

View File

@@ -230,7 +230,7 @@ void lease_update_from_configs(void)
if (lease->flags & (LEASE_TA | LEASE_NA)) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, 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_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL); lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);

View File

@@ -963,8 +963,7 @@ static char *set_prefix(char *arg)
return arg; return arg;
} }
static struct dhcp_netid * static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next)
dhcp_netid_create(const char *net, struct dhcp_netid *next)
{ {
struct dhcp_netid *tt; struct dhcp_netid *tt;
tt = opt_malloc(sizeof (struct dhcp_netid)); tt = opt_malloc(sizeof (struct dhcp_netid));
@@ -1029,6 +1028,7 @@ static void dhcp_config_free(struct dhcp_config *config)
} }
dhcp_netid_list_free(config->netid); dhcp_netid_list_free(config->netid);
dhcp_netid_free(config->filter);
if (config->flags & CONFIG_CLID) if (config->flags & CONFIG_CLID)
free(config->clid); free(config->clid);
@@ -3217,6 +3217,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->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL; new->hwaddr = NULL;
new->netid = NULL; new->netid = NULL;
new->filter = NULL;
new->clid = NULL; new->clid = NULL;
new->addr6 = NULL; new->addr6 = NULL;
@@ -3265,11 +3266,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
newlist->list = dhcp_netid_create(arg+4, NULL); newlist->list = dhcp_netid_create(arg+4, NULL);
} }
else if (strstr(arg, "tag:") == arg) else if (strstr(arg, "tag:") == arg)
{ new->filter = dhcp_netid_create(arg+4, new->filter);
dhcp_config_free(new);
ret_err(_("cannot match tags in --dhcp-host"));
}
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
{ {

View File

@@ -504,7 +504,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->op = BOOTREPLY; mess->op = BOOTREPLY;
config = find_config(daemon->dhcp_conf, context, clid, clid_len, config = find_config(daemon->dhcp_conf, context, clid, clid_len,
mess->chaddr, mess->hlen, mess->htype, NULL); mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid));
/* set "known" tag for known hosts */ /* set "known" tag for known hosts */
if (config) if (config)
@@ -514,7 +514,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &known_id; netid = &known_id;
} }
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, 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, run_tag_if(netid)))
{ {
known_id.net = "known-othernet"; known_id.net = "known-othernet";
known_id.next = netid; 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. */ to avoid impersonation by name. */
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
mess->chaddr, mess->hlen, mess->chaddr, mess->hlen,
mess->htype, hostname); mess->htype, hostname, run_tag_if(netid));
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{ {
config = new; config = new;

View File

@@ -526,7 +526,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
} }
if (state->clid && 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, run_tag_if(state->tags))) &&
have_config(config, CONFIG_NAME)) have_config(config, CONFIG_NAME))
{ {
state->hostname = config->hostname; state->hostname = config->hostname;
@@ -546,7 +547,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* Search again now we have a hostname. /* Search again now we have a hostname.
Only accept configs without CLID here, (it won't match) Only accept configs without CLID here, (it won't match)
to avoid impersonation by name. */ 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, run_tag_if(state->tags));
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
config = new; config = new;
} }
@@ -572,7 +573,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ignore = 1; ignore = 1;
} }
else if (state->clid && 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, run_tag_if(state->tags)))
{ {
known_id.net = "known-othernet"; known_id.net = "known-othernet";
known_id.next = state->tags; known_id.next = state->tags;