From 27ce754b3d7f2f0c297b0cede6b7ae57b0a0a0a5 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sat, 15 Jan 2022 17:57:57 +0000 Subject: [PATCH] Tidy previous commit and add manpage entries for new options. --- man/dnsmasq.8 | 8 ++++ src/dnsmasq.h | 5 +-- src/edns0.c | 113 ++++++++++++++++++++++++++------------------------ src/forward.c | 19 ++++----- 4 files changed, 77 insertions(+), 68 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index eecf5df..74cda38 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -742,6 +742,9 @@ have security and privacy implications. The warning about caching given for \fB--add-subnet\fP applies to \fB--add-mac\fP too. An alternative encoding of the MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter. .TP +.B --strip-mac +Remove any MAC address information already in downstream queries before forwarding upstream. +.TP .B --add-cpe-id= Add an arbitrary identifying string to DNS queries which are forwarded upstream. @@ -767,6 +770,11 @@ will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors. .B --add-subnet=1.2.3.4/24,1.2.3.4/24 will add 1.2.3.0/24 for both IPv4 and IPv6 requestors. .TP +.B --strip-subnet +Remove any subnet address already present in a downstream query before forwarding it upstream. If --add-subnet is set this also +ensures that any downstream-provided subnet is replaced by the one added by dnsmasq. Otherwise, dnsmaaq will NOT replace an +existing subnet in the query. +.TP .B --umbrella[=[deviceid:][,orgid:][,assetid:]] Embeds the requestor's IP address in DNS queries forwarded upstream. If device id or, asset id or organization id are specified, the information is diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 7384a1a..e77e1eb 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -724,7 +724,7 @@ struct hostsfile { #define FREC_NOREBIND 1 #define FREC_CHECKING_DISABLED 2 -#define FREC_HAS_SUBNET 4 +#define FREC_NO_CACHE 4 #define FREC_DNSKEY_QUERY 8 #define FREC_DS_QUERY 16 #define FREC_AD_QUESTION 32 @@ -733,7 +733,6 @@ struct hostsfile { #define FREC_TEST_PKTSZ 256 #define FREC_HAS_EXTRADATA 512 #define FREC_HAS_PHEADER 1024 -#define FREC_NO_CACHE 2048 #define HASH_SIZE 32 /* SHA-256 digest size */ @@ -1785,7 +1784,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace); size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit); size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, - union mysockaddr *source, time_t now, int *check_subnet, int *cacheable); + union mysockaddr *source, time_t now, int *cacheable); int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer); /* arp.c */ diff --git a/src/edns0.c b/src/edns0.c index 1599040..7591b78 100644 --- a/src/edns0.c +++ b/src/edns0.c @@ -264,49 +264,62 @@ static void encoder(unsigned char *in, char *out) out[3] = char64(in[2]); } +/* 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 */ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now, int *cacheablep) { - int maclen, replace = 2; /* can't get mac address, just delete any incoming. */ + int replace = 0, maclen = 0; unsigned char mac[DHCP_CHADDR_MAX]; - char encode[18]; /* handle 6 byte MACs */ + char encode[18]; /* handle 6 byte MACs ONLY */ - if ((maclen = find_mac(l3, mac, 1, now)) == 6) + if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6) { - replace = 1; - *cacheablep = 0; - - if (option_bool(OPT_MAC_HEX)) - print_mac(encode, mac, maclen); - else - { - encoder(mac, encode); - encoder(mac+3, encode+4); - encode[8] = 0; - } + if (option_bool(OPT_STRIP_MAC)) + replace = 1; + *cacheablep = 0; + + if (option_bool(OPT_MAC_HEX)) + print_mac(encode, mac, maclen); + else + { + encoder(mac, encode); + encoder(mac+3, encode+4); + encode[8] = 0; + } } + else if (option_bool(OPT_STRIP_MAC)) + replace = 2; - return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace); + if (replace != 0 || maclen == 6) + plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace); + + return plen; } +/* 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 */ static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, - union mysockaddr *l3, time_t now, int *cacheablep, const int replace) + union mysockaddr *l3, time_t now, int *cacheablep) { - int maclen; + int maclen = 0, replace = 0; unsigned char mac[DHCP_CHADDR_MAX]; - - if ((maclen = find_mac(l3, mac, 1, now)) != 0) + + if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0) { *cacheablep = 0; - plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace); + if (option_bool(OPT_STRIP_MAC)) + replace = 1; } - 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); - } + else if (option_bool(OPT_STRIP_MAC)) + replace = 2; + if (replace != 0 || maclen != 0) + plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace); + return plen; } @@ -383,15 +396,28 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, return len + 4; } +/* OPT_CLIENT_SUBNET = client subnet is added + OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced + OPT_STRIP_ECS = client subnet is removed */ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, - union mysockaddr *source, int *cacheable, const int replace) + union mysockaddr *source, int *cacheable) { /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */ - int len; + int replace = 0, len = 0; struct subnet_opt opt; - len = calc_subnet_opt(&opt, source, cacheable); + if (option_bool(OPT_CLIENT_SUBNET)) + { + if (option_bool(OPT_STRIP_ECS)) + replace = 1; + len = calc_subnet_opt(&opt, source, cacheable); + } + else if (option_bool(OPT_STRIP_ECS)) + replace = 2; + else + return plen; + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace); } @@ -499,24 +525,12 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned in the reply. Set *cacheable to zero if we add an option which the answer may depend on. */ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, - union mysockaddr *source, time_t now, int *check_subnet, int *cacheable) + union mysockaddr *source, time_t now, int *cacheable) { - *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, 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); + plen = add_mac(header, plen, limit, source, now, cacheable); + plen = add_dns_client(header, plen, limit, source, now, cacheable); if (daemon->dns_client_id) plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, @@ -525,16 +539,7 @@ 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, 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); - + plen = add_source_addr(header, plen, limit, source, cacheable); + return plen; } diff --git a/src/forward.c b/src/forward.c index 8d8b8fe..586deae 100644 --- a/src/forward.c +++ b/src/forward.c @@ -195,7 +195,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL); int old_src = 0, old_reply = 0; int first, last, start = 0; - int subnet, cacheable, forwarded = 0; + int cacheable, forwarded = 0; size_t edns0_len; unsigned char *pheader; int ede = EDE_UNSET; @@ -443,10 +443,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, { header->id = htons(forward->new_id); - plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable); - - if (subnet) - forward->flags |= FREC_HAS_SUBNET; + plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &cacheable); if (!cacheable) forward->flags |= FREC_NO_CACHE; @@ -624,7 +621,7 @@ static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domai static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind, int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader, - int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede) + union mysockaddr *query_source, unsigned char *limit, int ede) { unsigned char *pheader, *sizep; struct ipsets *ipsets = NULL, *nftsets = NULL; @@ -651,7 +648,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server /* Get extended RCODE. */ rcode |= sizep[2] << 4; - if (check_subnet && !check_source(header, plen, pheader, query_source)) + if (option_bool(OPT_CLIENT_SUBNET) && !check_source(header, plen, pheader, query_source)) { my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch")); return 0; @@ -1241,7 +1238,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, - forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source, + forward->flags & FREC_ADDED_PHEADER, &forward->frec_src.source, ((unsigned char *)header) + daemon->edns_pktsz, ede))) { struct frec_src *src; @@ -1928,7 +1925,7 @@ unsigned char *tcp_request(int confd, time_t now, int local_auth = 0; #endif int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0; - int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; + int cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; size_t m; unsigned short qtype; unsigned int gotname; @@ -2146,7 +2143,7 @@ unsigned char *tcp_request(int confd, time_t now, else start = master->last_server; - size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable); + size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable); #ifdef HAVE_DNSSEC if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC)) @@ -2224,7 +2221,7 @@ unsigned char *tcp_request(int confd, time_t now, m = process_reply(header, now, serv, (unsigned int)m, option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer, - ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr, ((unsigned char *)header) + 65536, ede); + ad_reqd, do_bit, added_pheader, &peer_addr, ((unsigned char *)header) + 65536, ede); } } }