From 616bebde88ec80cdc5196e74869ed3fe2bb4f33d Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 20 Dec 2020 22:10:06 +0100 Subject: [PATCH] Analyze original question and use it to decide whether we mock an A or AAAA reply when blocking Signed-off-by: DL6ER --- src/dnsmasq/forward.c | 5 +++-- src/dnsmasq_interface.c | 50 +++++++++++++++++++++++++++++++++++++++++ src/dnsmasq_interface.h | 2 ++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/dnsmasq/forward.c b/src/dnsmasq/forward.c index 4c2c5414..782963af 100644 --- a/src/dnsmasq/forward.c +++ b/src/dnsmasq/forward.c @@ -736,8 +736,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server { cache_secure = 0; union all_addr *addrp = NULL; - // Pretend this is an A type reply - unsigned int flags = F_IPV4; + // Extract IPv4/IPv6 information from the original question in the DNS + // header + unsigned int flags = FTL_extract_question_flags(header, n); FTL_get_blocking_metadata(&addrp, &flags); n = setup_reply(header, n, addrp, flags, daemon->local_ttl); } diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index c97b68d2..3e9e36f3 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -1956,6 +1956,56 @@ static void prepare_blocking_metadata(void) clearSetupVarsArray(); } +unsigned int FTL_extract_question_flags(struct dns_header *header, const size_t qlen) +{ + // Create working pointer + unsigned char *p = (unsigned char *)(header+1); + uint16_t qtype, qclass; + + // Go through the questions + for (uint16_t i = ntohs(header->qdcount); i != 0; i--) + { + // Prime dnsmasq flags + int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0; + + // Extract name from this question + char name[MAXDNAME]; + if (!extract_name(header, qlen, &p, name, 1, 4)) + break; // bad packet, go to fallback solution + + // Extract query type + GETSHORT(qtype, p); + GETSHORT(qclass, p); + + // Only further analyze IN questions here (not CHAOS, etc.) + if (qclass != C_IN) + continue; + + // Very simple decision: If the question is AAAA, the reply + // should be IPv6. We use IPv4 in all other cases + if(qtype == T_AAAA) + flags |= F_IPV6; + else + flags |= F_IPV4; + + // Debug logging if enabled + if(config.debug & DEBUG_QUERIES) + { + char *qtype_str = querystr(NULL, qtype); + logg("CNAME header: Question was %s %s", qtype_str, name); + } + + return flags; + } + + // Fall back to IPv4 (type A) when for the unlikely event that we cannot + // find any questions in this header + if(config.debug & DEBUG_QUERIES) + logg("CNAME header: No valid IN question found in header"); + + return F_IPV4; +} + // Called when a (forked) TCP worker is terminated by receiving SIGALRM // We close the dedicated database connection this client had opened // to avoid dangling database locks diff --git a/src/dnsmasq_interface.h b/src/dnsmasq_interface.h index 572395fc..e80de13c 100644 --- a/src/dnsmasq_interface.h +++ b/src/dnsmasq_interface.h @@ -52,6 +52,8 @@ void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, con #define FTL_CNAME(domain, cpp, id) _FTL_CNAME(domain, cpp, id, __FILE__, __LINE__) bool _FTL_CNAME(const char *domain, const struct crec *cpp, const int id, const char* file, const int line); +unsigned int FTL_extract_question_flags(struct dns_header *header, const size_t qlen); + void FTL_dnsmasq_reload(void); void FTL_fork_and_bind_sockets(struct passwd *ent_pw); void FTL_TCP_worker_created(const int confd, const char *iface_name);