From aaba66efbd3b4e7283993ca3718df47706a8549b Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 12 Apr 2023 22:55:14 +0100 Subject: Add --no-dhcpv4-interface and --no-dhcpv6-interface options. --- CHANGELOG | 3 +++ man/dnsmasq.8 | 9 ++++++++- src/dhcp-common.c | 2 +- src/dhcp.c | 2 +- src/dhcp6.c | 3 ++- src/dnsmasq.h | 5 ++++- src/network.c | 17 +++++++++++------ src/option.c | 13 +++++++++++++ src/radv.c | 9 ++++++--- src/tftp.c | 3 ++- 10 files changed, 51 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 52d8678..c0694eb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,9 @@ version 2.90 for IPv6. It's still possible to override this with --edns-packet-max for special circumstances. + Add --no-dhcpv4-interface and --no-dhcpv6-interface for + better control over which inetrfaces are providing DHCP service. + version 2.89 Fix bug introduced in 2.88 (commit fe91134b) which can result diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 37aea60..30429df 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -279,7 +279,14 @@ a default on installation, to allow unconfigured installations to be useful but also safe from being used for DNS amplification attacks. .TP .B \-2, --no-dhcp-interface= -Do not provide DHCP or TFTP on the specified interface, but do provide DNS service. +Do not provide DHCP, TFTP or router advertisement on the specified interface, but do provide DNS service. +.TP +.B --no-dhcpv4-interface= +Disable only IPv4 DHCP on the specified interface. +.TP +.B +--no-dhcpv6-interface= +Disable IPv6 DHCP and router advertisement on the specified interface. .TP .B \-a, --listen-address= Listen on the given IP address(es). Both diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 360cdc5..b004e40 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -557,7 +557,7 @@ char *whichdevice(void) return NULL; for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next) - if (iface->dhcp_ok) + if (iface->dhcp4_ok || iface->dhcp6_ok) { if (!found) found = iface; diff --git a/src/dhcp.c b/src/dhcp.c index 7126b29..c7dd33b 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -297,7 +297,7 @@ void dhcp_packet(time_t now, int pxe_fd) } for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) + if (tmp->name && (tmp->flags & INAME_4) && wildcard_match(tmp->name, ifr.ifr_name)) return; /* unlinked contexts/relays are marked by context->current == context */ diff --git a/src/dhcp6.c b/src/dhcp6.c index 9ae92da..7eeef03 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -159,7 +159,8 @@ void dhcp6_packet(time_t now) return; for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) + if (tmp->name && (tmp->flags & INAME_6) && + wildcard_match(tmp->name, ifr.ifr_name)) return; parm.current = NULL; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 2a57969..2f95c12 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -648,7 +648,8 @@ struct allowlist { struct irec { union mysockaddr addr; struct in_addr netmask; /* only valid for IPv4 */ - int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found, label; + int tftp_ok, dhcp4_ok, dhcp6_ok, mtu, done, warned, dad; + int dns_auth, index, multicast_done, found, label; char *name; struct irec *next; }; @@ -669,6 +670,8 @@ struct iname { }; #define INAME_USED 1 +#define INAME_4 2 +#define INAME_6 4 struct rrlist { unsigned short rr; diff --git a/src/network.c b/src/network.c index 9c5c613..ca9fada 100644 --- a/src/network.c +++ b/src/network.c @@ -244,7 +244,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, int loopback; struct ifreq ifr; int tftp_ok = !!option_bool(OPT_TFTP); - int dhcp_ok = 1; + int dhcp4_ok = 1; + int dhcp6_ok = 1; int auth_dns = 0; int is_label = 0; #if defined(HAVE_DHCP) || defined(HAVE_TFTP) @@ -260,7 +261,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, loopback = ifr.ifr_flags & IFF_LOOPBACK; if (loopback) - dhcp_ok = 0; + dhcp4_ok = dhcp6_ok = 0; if (!label) label = ifr.ifr_name; @@ -532,14 +533,17 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, if (auth_dns) { tftp_ok = 0; - dhcp_ok = 0; + dhcp4_ok = dhcp6_ok = 0; } else for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) { tftp_ok = 0; - dhcp_ok = 0; + if (tmp->flags & INAME_4) + dhcp4_ok = 0; + if (tmp->flags & INAME_6) + dhcp6_ok = 0; } #endif @@ -566,7 +570,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, iface->addr = *addr; iface->netmask = netmask; iface->tftp_ok = tftp_ok; - iface->dhcp_ok = dhcp_ok; + iface->dhcp4_ok = dhcp4_ok; + iface->dhcp6_ok = dhcp6_ok; iface->dns_auth = auth_dns; iface->mtu = mtu; iface->dad = !!(iface_flags & IFACE_TENTATIVE); @@ -1295,7 +1300,7 @@ void join_multicast(int dienow) struct irec *iface, *tmp; for (iface = daemon->interfaces; iface; iface = iface->next) - if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp_ok && !iface->multicast_done) + if (iface->addr.sa.sa_family == AF_INET6 && iface->dhcp6_ok && !iface->multicast_done) { /* There's an irec per address but we only want to join for multicast once per interface. Weed out duplicates. */ diff --git a/src/option.c b/src/option.c index 94bc682..8322725 100644 --- a/src/option.c +++ b/src/option.c @@ -188,6 +188,8 @@ struct myoption { #define LOPT_NO_IDENT 379 #define LOPT_CACHE_RR 380 #define LOPT_FILTER_RR 381 +#define LOPT_NO_DHCP6 382 +#define LOPT_NO_DHCP4 383 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -248,6 +250,8 @@ static const struct myoption opts[] = { "query-port", 1, 0, 'Q' }, { "except-interface", 1, 0, 'I' }, { "no-dhcp-interface", 1, 0, '2' }, + { "no-dhcpv4-interface", 1, 0, LOPT_NO_DHCP4 }, + { "no-dhcpv6-interface", 1, 0, LOPT_NO_DHCP6 }, { "domain-needed", 0, 0, 'D' }, { "dhcp-lease-max", 1, 0, 'X' }, { "bind-interfaces", 0, 0, 'z' }, @@ -478,6 +482,8 @@ static struct { { '1', ARG_ONE, "[=]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL }, { LOPT_UBUS, ARG_ONE, "[=]", gettext_noop("Enable the UBus interface."), NULL }, { '2', ARG_DUP, "", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL }, + { LOPT_NO_DHCP6, ARG_DUP, "", gettext_noop("Do not provide DHCPv6 on this interface."), NULL }, + { LOPT_NO_DHCP4, ARG_DUP, "", gettext_noop("Do not provide DHCPv4 on this interface."), NULL }, { '3', ARG_DUP, "[=tag:]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL }, { '4', ARG_DUP, "set:,", gettext_noop("Map MAC address (with wildcards) to option set."), NULL }, { LOPT_BRIDGE, ARG_DUP, ",..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL }, @@ -2846,10 +2852,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma case 'I': /* --except-interface */ case '2': /* --no-dhcp-interface */ + case LOPT_NO_DHCP6: /* --no-dhcpv6-interface */ + case LOPT_NO_DHCP4: /* --no-dhcpv4-interface */ do { struct iname *new = opt_malloc(sizeof(struct iname)); comma = split(arg); new->name = opt_string_alloc(arg); + new->flags = INAME_4 | INAME_6; if (option == 'I') { new->next = daemon->if_except; @@ -2862,6 +2871,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma } else { + if (option == LOPT_NO_DHCP6) + new->flags &= ~INAME_4; + if (option == LOPT_NO_DHCP4) + new->flags &= ~INAME_6; new->next = daemon->dhcp_except; daemon->dhcp_except = new; } diff --git a/src/radv.c b/src/radv.c index 49b41d8..a4af344 100644 --- a/src/radv.c +++ b/src/radv.c @@ -186,7 +186,8 @@ void icmp6_packet(time_t now) return; for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, interface)) + if (tmp->name && (tmp->flags & INAME_6) && + wildcard_match(tmp->name, interface)) return; if (packet[1] != 0) @@ -835,7 +836,8 @@ time_t periodic_ra(time_t now) { struct iname *tmp; for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, param.name)) + if (tmp->name && (tmp->flags & INAME_6) && + wildcard_match(tmp->name, param.name)) break; if (!tmp) { @@ -934,7 +936,8 @@ static int iface_search(struct in6_addr *local, int prefix, return 1; for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, param->name)) + if (tmp->name && (tmp->flags & INAME_6) && + wildcard_match(tmp->name, param->name)) return 1; for (context = daemon->dhcp6; context; context = context->next) diff --git a/src/tftp.c b/src/tftp.c index 8bbaea0..caf077f 100644 --- a/src/tftp.c +++ b/src/tftp.c @@ -228,7 +228,8 @@ void tftp_request(struct listener *listen, time_t now) #ifdef HAVE_DHCP /* allowed interfaces are the same as for DHCP */ for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) - if (tmp->name && wildcard_match(tmp->name, name)) + if (tmp->name && (tmp->flags & (INAME_4 | INAME_6) == (INAME_4 | INAME_6)) && + wildcard_match(tmp->name, name)) return; #endif } -- cgit v1.2.1