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

@@ -76,7 +76,10 @@ version 2.81
address, only one gets the "static" address, but with this
fix, enough addresses can be reserved for all the stages of the
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

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.
.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
with a particular hardware address to be always allocated the same
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
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.
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
wildcard bytes, so for example
.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;
}
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)
static struct dhcp_config *find_config_match(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, int tag_not_needed)
{
int count, new;
struct dhcp_config *config, *candidate;
@@ -320,7 +321,9 @@ 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))
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
/* 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() */
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))
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
}
@@ -336,14 +340,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
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))
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return 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))
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
@@ -352,7 +358,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
/* use match with fewest wildcard octets */
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)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
@@ -366,6 +373,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
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)
{
/* 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 */
char *hostname, *domain;
struct dhcp_netid_list *netid;
struct dhcp_netid *filter;
#ifdef HAVE_DHCP6
struct addrlist *addr6;
#endif
@@ -1555,7 +1556,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 *filter);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);

View File

@@ -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);

View File

@@ -963,8 +963,7 @@ static char *set_prefix(char *arg)
return arg;
}
static struct dhcp_netid *
dhcp_netid_create(const char *net, struct dhcp_netid *next)
static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next)
{
struct dhcp_netid *tt;
tt = opt_malloc(sizeof (struct dhcp_netid));
@@ -1029,7 +1028,8 @@ static void dhcp_config_free(struct dhcp_config *config)
}
dhcp_netid_list_free(config->netid);
dhcp_netid_free(config->filter);
if (config->flags & 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->hwaddr = NULL;
new->netid = NULL;
new->filter = NULL;
new->clid = 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);
}
else if (strstr(arg, "tag:") == arg)
{
dhcp_config_free(new);
ret_err(_("cannot match tags in --dhcp-host"));
}
new->filter = dhcp_netid_create(arg+4, new->filter);
#ifdef HAVE_DHCP6
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;
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 */
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, run_tag_if(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, run_tag_if(netid));
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{
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 &&
(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))
{
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.
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, run_tag_if(state->tags));
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
config = new;
}
@@ -572,7 +573,8 @@ 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, run_tag_if(state->tags)))
{
known_id.net = "known-othernet";
known_id.next = state->tags;