Add --shared-network DHCP configuration.

This commit is contained in:
Simon Kelley committed 2019-03-27 22:33:28 +00:00
1 parent 305ffb5ef0
commit ae5b7e04a1
8 files changed
+333 -135

No files matched your search

+63 -13
View File
@@ -507,33 +507,83 @@ static int check_listen_addrs(struct in_addr local, int if_index, char *label,
Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
(void)label;
for (context = daemon->dhcp; context; context = context->next)
{
if (!(context->flags & CONTEXT_NETMASK) &&
(is_same_net(local, context->start, netmask) ||
is_same_net(local, context->end, netmask)))
if (!(context->flags & CONTEXT_NETMASK) &&
(is_same_net(addr, context->start, netmask) ||
is_same_net(addr, context->end, netmask)))
{
if (context->netmask.s_addr != netmask.s_addr &&
!(is_same_net(local, context->start, netmask) &&
is_same_net(local, context->end, netmask)))
!(is_same_net(addr, context->start, netmask) &&
is_same_net(addr, context->end, netmask)))
{
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
}
context->netmask = netmask;
context->netmask = netmask;
}
}
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct shared_network *share;
(void)label;
for (share = daemon->shared_networks; share; share = share->next)
{
#ifdef HAVE_DHCP6
if (share->shared_addr.s_addr == 0)
continue;
#endif
if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (share->match_addr.s_addr != local.s_addr)
continue;
}
for (context = daemon->dhcp; context; context = context->next)
{
if (context->netmask.s_addr != 0 &&
is_same_net(share->shared_addr, context->start, context->netmask) &&
is_same_net(share->shared_addr, context->end, context->netmask))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
/* For a shared network, we have no way to guess what the default route should be. */
context->router.s_addr = 0;
context->local = local; /* Use configured address for Server Identifier */
context->current = param->current;
param->current = context;
}
if (!(context->flags & CONTEXT_BRDCAST))
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
}
}
}
guess_range_netmask(local, netmask);
for (context = daemon->dhcp; context; context = context->next)
{
if (context->netmask.s_addr != 0 &&
is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask))
+101 -76
View File
@@ -299,89 +299,114 @@ static int complete_context6(struct in6_addr *local, int prefix,
unsigned int valid, void *vparam)
{
struct dhcp_context *context;
struct shared_network *share;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->ll_addr = *local;
else if (IN6_IS_ADDR_ULA(local))
param->ula_addr = *local;
if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
{
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
struct dhcp_context *tmp, **up;
/* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
if (if_index != param->ind)
return 1;
if (IN6_IS_ADDR_LINKLOCAL(local))
param->ll_addr = *local;
else if (IN6_IS_ADDR_ULA(local))
param->ula_addr = *local;
}
return 1;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
context->current == context)
{
if (is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
struct dhcp_context *tmp, **up;
/* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
else
{
for (share = daemon->shared_networks; share; share = share->next)
{
/* IPv4 shared_address - ignore */
if (share->shared_addr.s_addr != 0)
continue;
if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (!IN6_ARE_ADDR_EQUAL(&share->match_addr6, local))
continue;
}
if (is_same_net6(&share->shared_addr6, &context->start6, context->prefix) &&
is_same_net6(&share->shared_addr6, &context->end6, context->prefix))
{
context->current = param->current;
param->current = context;
context->local6 = *local;
context->preferred = context->flags & CONTEXT_DEPRECATE ? 0 :0xffffffff;
context->valid = 0xffffffff;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
+11
View File
@@ -910,6 +910,16 @@ struct dhcp_context {
struct dhcp_context *next, *current;
};
struct shared_network {
int if_index;
struct in_addr match_addr, shared_addr;
#ifdef HAVE_DHCP6
/* shared_addr == 0 for IP6 entries. */
struct in6_addr match_addr6, shared_addr6;
#endif
struct shared_network *next;
};
#define CONTEXT_STATIC (1u<<0)
#define CONTEXT_NETMASK (1u<<1)
#define CONTEXT_BRDCAST (1u<<2)
@@ -1107,6 +1117,7 @@ extern struct daemon {
struct ping_result *ping_results;
FILE *lease_stream;
struct dhcp_bridge *bridges;
struct shared_network *shared_networks;
#ifdef HAVE_DHCP6
int duid_len;
unsigned char *duid;
+41
View File
@@ -166,6 +166,7 @@ struct myoption {
#define LOPT_UBUS 354
#define LOPT_NAME_MATCH 355
#define LOPT_CAA 356
#define LOPT_SHARED_NET 357
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -259,6 +260,7 @@ static const struct myoption opts[] =
{ "ptr-record", 1, 0, LOPT_PTR },
{ "naptr-record", 1, 0, LOPT_NAPTR },
{ "bridge-interface", 1, 0 , LOPT_BRIDGE },
{ "shared-network", 1, 0, LOPT_SHARED_NET },
{ "dhcp-option-force", 1, 0, LOPT_FORCE },
{ "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
{ "log-dhcp", 0, 0, LOPT_LOG_OPTS },
@@ -431,6 +433,7 @@ static struct {
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
{ LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
{ LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL},
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
{ LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
@@ -2873,6 +2876,44 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
#ifdef HAVE_DHCP
case LOPT_SHARED_NET: /* --shared-network */
{
struct shared_network *new = opt_malloc(sizeof(struct shared_network));
#ifdef HAVE_DHCP6
new->shared_addr.s_addr = 0;
#endif
new->if_index = 0;
if (!(comma = split(arg)))
{
snerr:
free(new);
ret_err(_("bad shared-network"));
}
if (inet_pton(AF_INET, comma, &new->shared_addr))
{
if (!inet_pton(AF_INET, arg, &new->match_addr) &&
!(new->if_index = if_nametoindex(arg)))
goto snerr;
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, comma, &new->shared_addr6))
{
if (!inet_pton(AF_INET6, arg, &new->match_addr6) &&
!(new->if_index = if_nametoindex(arg)))
goto snerr;
}
#endif
else
goto snerr;
new->next = daemon->shared_networks;
daemon->shared_networks = new;
break;
}
case 'F': /* --dhcp-range */
{
int k, leasepos = 2;
+61 -36
View File
@@ -274,8 +274,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
{
struct dhcp_context *context_tmp, *context_new = NULL;
struct shared_network *share = NULL;
struct in_addr addr;
int force = 0;
int force = 0, via_relay = 0;
if (subnet_addr.s_addr)
{
@@ -286,6 +287,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
addr = mess->giaddr;
force = 1;
via_relay = 1;
}
else
{
@@ -302,42 +304,65 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
if (!context_new)
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
{
struct in_addr netmask = context_tmp->netmask;
{
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
{
struct in_addr netmask = context_tmp->netmask;
/* guess the netmask for relayed networks */
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
{
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xff000000);
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffff0000);
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffffff00);
}
/* guess the netmask for relayed networks */
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
{
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xff000000);
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffff0000);
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffffff00);
}
/* This section fills in context mainly when a client which is on a remote (relayed)
network renews a lease without using the relay, after dnsmasq has restarted. */
if (netmask.s_addr != 0 &&
is_same_net(addr, context_tmp->start, netmask) &&
is_same_net(addr, context_tmp->end, netmask))
{
context_tmp->netmask = netmask;
if (context_tmp->local.s_addr == 0)
context_tmp->local = fallback;
if (context_tmp->router.s_addr == 0)
context_tmp->router = mess->giaddr;
/* fill in missing broadcast addresses for relayed ranges */
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
context_tmp->current = context_new;
context_new = context_tmp;
}
}
/* check to see is a context is OK because of a shared address on
the relayed subnet. */
if (via_relay)
for (share = daemon->shared_networks; share; share = share->next)
{
#ifdef HAVE_DHCP6
if (share->shared_addr.s_addr == 0)
continue;
#endif
if (share->if_index != 0 ||
share->match_addr.s_addr != mess->giaddr.s_addr)
continue;
if (netmask.s_addr != 0 &&
is_same_net(share->shared_addr, context_tmp->start, netmask) &&
is_same_net(share->shared_addr, context_tmp->end, netmask))
break;
}
/* This section fills in context mainly when a client which is on a remote (relayed)
network renews a lease without using the relay, after dnsmasq has restarted. */
if (share ||
(netmask.s_addr != 0 &&
is_same_net(addr, context_tmp->start, netmask) &&
is_same_net(addr, context_tmp->end, netmask)))
{
context_tmp->netmask = netmask;
if (context_tmp->local.s_addr == 0)
context_tmp->local = fallback;
if (context_tmp->router.s_addr == 0 && !share)
context_tmp->router = mess->giaddr;
/* fill in missing broadcast addresses for relayed ranges */
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
context_tmp->current = context_new;
context_new = context_tmp;
}
}
}
if (context_new || force)
context = context_new;
}
+30 -10
View File
@@ -134,21 +134,41 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
else
{
struct dhcp_context *c;
struct shared_network *share = NULL;
state->context = NULL;
if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
!IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
!IN6_IS_ADDR_MULTICAST(state->link_address))
for (c = daemon->dhcp6; c; c = c->next)
if ((c->flags & CONTEXT_DHCP) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(state->link_address, &c->start6, c->prefix) &&
is_same_net6(state->link_address, &c->end6, c->prefix))
{
c->preferred = c->valid = 0xffffffff;
c->current = state->context;
state->context = c;
}
{
for (share = daemon->shared_networks; share; share = share->next)
{
if (share->shared_addr.s_addr != 0)
continue;
if (share->if_index != 0 ||
!IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_addr6))
continue;
if ((c->flags & CONTEXT_DHCP) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(&share->shared_addr6, &c->start6, c->prefix) &&
is_same_net6(&share->shared_addr6, &c->end6, c->prefix))
break;
}
if (share ||
((c->flags & CONTEXT_DHCP) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(state->link_address, &c->start6, c->prefix) &&
is_same_net6(state->link_address, &c->end6, c->prefix)))
{
c->preferred = c->valid = 0xffffffff;
c->current = state->context;
state->context = c;
}
}
if (!state->context)
{