Hey Simon, a series of patches (multiple mails) follows. This is the first one:
Strip EDNS(0) Client Subnet / MAC information if --strip-subnet or --strip-mac is set. If BOTH the add and strip options are set, incoming EDNS0 options are REPLACED. This ensures we do not unintentionally forward client information somewhere upstream when ECS is used in lower DNS layers in our local network. Some upstream servers, for instance, Google DNS, even refuse to answer when ECS contains a 192.168.0.0/16 address. Best, Dominik
From cb72bf20ce317a8d4c727d7818b2e20b33832eae Mon Sep 17 00:00:00 2001 From: Dominik Derigs <dl...@dl6er.de> Date: Fri, 7 Jan 2022 06:11:53 +0100 Subject: [PATCH] Strip EDNS(0) Client Subnet / MAC information if --strip-subnet or --strip-mac is set. If both the add and strip options are set, incoming EDNS0 options are replaced. This ensures we do not unintentionally forward client information somewhere upstream when ECS is used in lower DNS layers in our local network. Signed-off-by: DL6ER <dl...@dl6er.de> --- src/dnsmasq.h | 4 +++- src/edns0.c | 33 ++++++++++++++++++++++++++------- src/option.c | 6 ++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 1b00298..7384a1a 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -277,7 +277,9 @@ struct event_desc { #define OPT_QUIET_TFTP 66 #define OPT_FILTER_A 67 #define OPT_FILTER_AAAA 68 -#define OPT_LAST 69 +#define OPT_STRIP_ECS 69 +#define OPT_STRIP_MAC 70 +#define OPT_LAST 71 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) diff --git a/src/edns0.c b/src/edns0.c index 5de6cb2..1599040 100644 --- a/src/edns0.c +++ b/src/edns0.c @@ -291,7 +291,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, - union mysockaddr *l3, time_t now, int *cacheablep) + union mysockaddr *l3, time_t now, int *cacheablep, const int replace) { int maclen; unsigned char mac[DHCP_CHADDR_MAX]; @@ -299,8 +299,13 @@ static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *lim if ((maclen = find_mac(l3, mac, 1, now)) != 0) { *cacheablep = 0; - plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0); + plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace); } + else if(replace > 0) + { + /* Asked to replace MAC address but it is not available here. We just remove whatever might be there */ + plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_MAC, NULL, 0, 0, 2); + } return plen; } @@ -378,7 +383,8 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, return len + 4; } -static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable) +static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, + union mysockaddr *source, int *cacheable, const int replace) { /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ @@ -386,7 +392,7 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c struct subnet_opt opt; len = calc_subnet_opt(&opt, source, cacheable); - return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0); + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace); } int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer) @@ -498,11 +504,19 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l *check_subnet = 0; *cacheable = 1; + /* OPT_ADD_MAC = MAC is added (if available) + OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed + OPT_STRIP_MAC = MAC is removed */ if (option_bool(OPT_ADD_MAC)) - plen = add_mac(header, plen, limit, source, now, cacheable); - + plen = add_mac(header, plen, limit, source, now, cacheable, option_bool(OPT_STRIP_MAC) ? 1 : 0); + else if (option_bool(OPT_STRIP_MAC)) + plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_MAC, NULL, 0, 0, 2); + + /* Use --strip-mac also for --add-mac=hex and --add-mac=text */ if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) plen = add_dns_client(header, plen, limit, source, now, cacheable); + else if (option_bool(OPT_STRIP_MAC)) + plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_NOMDEVICEID, NULL, 0, 0, 2); if (daemon->dns_client_id) plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, @@ -511,11 +525,16 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l if (option_bool(OPT_UMBRELLA)) plen = add_umbrella_opt(header, plen, limit, source, cacheable); + /* OPT_CLIENT_SUBNET = client subnet is added + OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced + OPT_STRIP_ECS = client subnet is removed */ if (option_bool(OPT_CLIENT_SUBNET)) { - plen = add_source_addr(header, plen, limit, source, cacheable); + plen = add_source_addr(header, plen, limit, source, cacheable, option_bool(OPT_STRIP_ECS) ? 1 : 0); *check_subnet = 1; } + else if (option_bool(OPT_STRIP_ECS)) + plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_CLIENT_SUBNET, NULL, 0, 0, 2); return plen; } diff --git a/src/option.c b/src/option.c index 7134ee7..6942432 100644 --- a/src/option.c +++ b/src/option.c @@ -177,6 +177,8 @@ struct myoption { #define LOPT_NFTSET 368 #define LOPT_FILTER_A 369 #define LOPT_FILTER_AAAA 370 +#define LOPT_STRIP_SBNET 371 +#define LOPT_STRIP_MAC 372 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -314,7 +316,9 @@ static const struct myoption opts[] = { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "add-mac", 2, 0, LOPT_ADD_MAC }, + { "strip-mac", 0, 0, LOPT_STRIP_MAC }, { "add-subnet", 2, 0, LOPT_ADD_SBNET }, + { "strip-subnet", 0, 0, LOPT_STRIP_SBNET }, { "add-cpe-id", 1, 0 , LOPT_CPE_ID }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, @@ -501,7 +505,9 @@ static struct { { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, + { LOPT_STRIP_MAC, OPT_STRIP_MAC, NULL, gettext_noop("Strip MAC information from queries."), NULL }, { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL }, + { LOPT_STRIP_SBNET, OPT_STRIP_ECS, NULL, gettext_noop("Strip ECS information from queries."), NULL }, { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL }, { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, -- 2.25.1
_______________________________________________ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss