From 48658ebc54fb5e29c93923352f89bc67ae276518 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 23 Apr 2025 16:47:50 +0100 Subject: [PATCH] Add address filtering for leasequery. --- man/dnsmasq.8 | 5 +++-- src/dhcp.c | 2 +- src/dnsmasq.h | 3 +-- src/option.c | 22 +++++++++++++++++++--- src/rfc2131.c | 18 +++++++++++++++++- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index b2c3d9b..1043ace 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1438,9 +1438,10 @@ DHCP options. This make extra space available in the DHCP packet for options but can, rarely, confuse old or broken clients. This flag forces "simple and safe" behaviour to avoid problems in such a case. .TP -.B --leasequery +.B --leasequery[=] Enable RFC 4388 leasequery. The dnsmasq DHCP server will answer LEASEQUERY messages from DHCP relays -when this option is given. To correctly answer lease queries it is necessary to store extra data in +when this option is given. If an address is given, only queries from a relay at that address are allowed. Repeat +the --leasequery option to specify multiple addresses. To correctly answer lease queries it is necessary to store extra data in the lease database, and this is also enabled by the \fB--leasequery\fP option. The extra fields (agent-info and vendorclass) are stored in the leases file in a somewhat backwards compatible manner. Enabling and then disabling leasequery will not cause problems; the extra information will be aged diff --git a/src/dhcp.c b/src/dhcp.c index e25e3b1..35541de 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -384,7 +384,7 @@ void dhcp_packet(time_t now, int pxe_fd) { /* Send to BOOTP relay. */ if (is_relay_use_source) - /* restore as-recieved value */ + /* restore as-received value */ mess->giaddr.s_addr = INADDR_BROADCAST; else { diff --git a/src/dnsmasq.h b/src/dnsmasq.h index e346b2c..b379d27 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -854,7 +854,6 @@ struct dhcp_lease { char *old_hostname; /* hostname before it moved to another lease */ int flags; time_t expires; /* lease expiry */ - time_t last_transaction; #ifdef HAVE_BROKEN_RTC unsigned int length; #endif @@ -1187,7 +1186,7 @@ extern struct daemon { char *runfile; char *lease_change_command; struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces; - struct bogus_addr *bogus_addr, *ignore_addr; + struct bogus_addr *bogus_addr, *ignore_addr, *leasequery_addr; struct server *servers, *servers_tail, *local_domains, **serverarray; struct rebind_domain *no_rebind; int server_has_wildcard; diff --git a/src/option.c b/src/option.c index a021a2c..5b68632 100644 --- a/src/option.c +++ b/src/option.c @@ -395,7 +395,7 @@ static const struct myoption opts[] = { "use-stale-cache", 2, 0 , LOPT_STALE_CACHE }, { "no-ident", 0, 0, LOPT_NO_IDENT }, { "max-tcp-connections", 1, 0, LOPT_MAX_PROCS }, - { "leasequery", 0, 0, LOPT_LEASEQUERY }, + { "leasequery", 2, 0, LOPT_LEASEQUERY }, { NULL, 0, 0, 0 } }; @@ -501,7 +501,7 @@ static struct { { '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 }, { LOPT_SHARED_NET, ARG_DUP, "|,", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL}, - { LOPT_LEASEQUERY, OPT_LEASEQUERY, NULL, gettext_noop("Enable RFC 4388 leasequery functions for DHCPv4"), NULL}, + { LOPT_LEASEQUERY, ARG_DUP, "[]", gettext_noop("Enable RFC 4388 leasequery functions for DHCPv4"), NULL }, { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL }, { '6', ARG_ONE, "", 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 }, @@ -2915,7 +2915,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma arg = comma; } while (arg); break; - + +#ifdef HAVE_DHCP +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + case LOPT_LEASEQUERY: + set_option_bool(OPT_LEASEQUERY); + if (!arg) + break; +#pragma GCC diagnostic pop +#endif case 'B': /* --bogus-nxdomain */ case LOPT_IGNORE_ADDR: /* --ignore-address */ { @@ -2951,6 +2960,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma baddr->next = daemon->bogus_addr; daemon->bogus_addr = baddr; } +#ifdef HAVE_DHCP + else if (option == LOPT_LEASEQUERY) + { + baddr->next = daemon->leasequery_addr; + daemon->leasequery_addr = baddr; + } +#endif else { baddr->next = daemon->ignore_addr; diff --git a/src/rfc2131.c b/src/rfc2131.c index 70cbc34..b45ffcf 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -1062,8 +1062,24 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, if (leasequery_source.s_addr == 0) return 0; - daemon->metrics[METRIC_DHCPLEASEQUERY]++; inet_ntop(AF_INET, &leasequery_source, daemon->workspacename, ADDRSTRLEN); + + if (daemon->leasequery_addr) + { + struct bogus_addr *baddrp; + + for (baddrp = daemon->leasequery_addr; baddrp; baddrp = baddrp->next) + if (!baddrp->is6 && baddrp->addr.addr4.s_addr == leasequery_source.s_addr) + break; + + if (!baddrp) + { + my_syslog(MS_DHCP | LOG_WARNING, _("leasequery from %s not permitted"), daemon->workspacename); + return 0; + } + } + + daemon->metrics[METRIC_DHCPLEASEQUERY]++; log_packet("DHCPLEASEQUERY", mess->ciaddr.s_addr ? &mess->ciaddr : NULL, emac_len != 0 ? emac : NULL, emac_len, iface_name, "from ", daemon->workspacename, mess->xid);