Simplify EDNS handling code and also interpret replies received from upstream

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER 2023-04-07 17:51:38 +02:00
parent 6a1de9fdc0
commit 37de8662ea
No known key found for this signature in database
GPG Key ID: 00135ACBD90B28DD
5 changed files with 64 additions and 45 deletions

View File

@ -783,7 +783,8 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
a.log.rcode = rcode;
a.log.ede = ede;
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL, 0);
FTL_parse_pseudoheaders(pheader, (size_t)plen);
return resize_packet(header, n, pheader, plen);
}
@ -1750,9 +1751,8 @@ void receive_query(struct listener *listen, time_t now)
have_mark = get_incoming_mark(&source_addr, &dst_addr, /* istcp: */ 0, &mark);
#endif
//********************** Pi-hole modification **********************//
ednsData edns = { 0 };
if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
FTL_parse_pseudoheaders(header, n, &source_addr, &edns);
if ((pheader = find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL)))
FTL_parse_pseudoheaders(pheader, (size_t)n);
//******************************************************************//
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
@ -1763,7 +1763,7 @@ void receive_query(struct listener *listen, time_t now)
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
&source_addr, auth_dns ? "auth" : "query", type);
piholeblocked = FTL_new_query(F_QUERY | F_FORWARD , daemon->namebuff,
&source_addr, auth_dns ? "auth" : "query", type, daemon->log_display_id, &edns, UDP);
&source_addr, auth_dns ? "auth" : "query", type, daemon->log_display_id, UDP);
#ifdef HAVE_CONNTRACK
is_single_query = 1;
@ -2298,9 +2298,9 @@ unsigned char *tcp_request(int confd, time_t now,
no_cache_dnssec = 1;
//********************** Pi-hole modification **********************//
ednsData edns = { 0 };
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
FTL_parse_pseudoheaders(header, size, &peer_addr, &edns);
unsigned char *pheader = NULL;
if ((pheader = find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL)))
FTL_parse_pseudoheaders(pheader, (size_t)size);
//******************************************************************//
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
@ -2320,7 +2320,7 @@ unsigned char *tcp_request(int confd, time_t now,
&peer_addr, auth_dns ? "auth" : "query", qtype);
piholeblocked = FTL_new_query(F_QUERY | F_FORWARD, daemon->namebuff,
&peer_addr, auth_dns ? "auth" : "query", qtype, daemon->log_display_id, &edns, TCP);
&peer_addr, auth_dns ? "auth" : "query", qtype, daemon->log_display_id, TCP);
#ifdef HAVE_AUTH
/* find queries for zones we're authoritative for, and answer them directly */

View File

@ -128,8 +128,6 @@ void FTL_hook(unsigned int flags, const char *name, union all_addr *addr, char *
if(!config.show_dnssec)
return;
const ednsData edns = { 0 };
// Type is overloaded with port since 2d65d55, so we have to
// derive the real query type from the arg string
unsigned short qtype = type;
@ -158,7 +156,7 @@ void FTL_hook(unsigned int flags, const char *name, union all_addr *addr, char *
arg = (char*)"dnssec-unknown";
}
_FTL_new_query(flags, name, NULL, arg, qtype, id, &edns, INTERNAL, file, line);
_FTL_new_query(flags, name, NULL, arg, qtype, id, INTERNAL, file, line);
// forwarded upstream (type is used to store the upstream port)
FTL_forwarded(flags, name, addr, type, id, path, line);
}
@ -464,7 +462,7 @@ static bool is_pihole_domain(const char *domain)
bool _FTL_new_query(const unsigned int flags, const char *name,
union mysockaddr *addr, char *arg,
const unsigned short qtype, const int id,
const ednsData *edns, const enum protocol proto,
const enum protocol proto,
const char* file, const int line)
{
// Create new query in data structure
@ -596,6 +594,7 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
in_port_t clientPort = daemon->port;
bool internal_query = false;
char clientIP[ADDRSTRLEN+1] = { 0 };
ednsData *edns = getEDNS();
if(config.edns0_ecs && edns && edns->client_set)
{
// Use ECS provided client
@ -3345,7 +3344,7 @@ int check_struct_sizes(void)
result += check_one_struct("clientsData", sizeof(clientsData), 672, 648);
result += check_one_struct("domainsData", sizeof(domainsData), 24, 20);
result += check_one_struct("DNSCacheData", sizeof(DNSCacheData), 16, 16);
result += check_one_struct("ednsData", sizeof(ednsData), 72, 72);
result += check_one_struct("ednsData", sizeof(ednsData), 76, 76);
result += check_one_struct("overTimeData", sizeof(overTimeData), 32, 24);
result += check_one_struct("regexData", sizeof(regexData), 64, 48);
result += check_one_struct("SharedMemory", sizeof(SharedMemory), 24, 12);

View File

@ -23,8 +23,8 @@ void FTL_hook(unsigned int flags, const char *name, union all_addr *addr, char *
#define FTL_iface(iface, addr, addrfamily) _FTL_iface(iface, addr, addrfamily, __FILE__, __LINE__)
void _FTL_iface(struct irec *recviface, const union all_addr *addr, const sa_family_t addrfamily, const char* file, const int line);
#define FTL_new_query(flags, name, addr, arg, qtype, id, edns, proto) _FTL_new_query(flags, name, addr, arg, qtype, id, edns, proto, __FILE__, __LINE__)
bool _FTL_new_query(const unsigned int flags, const char *name, union mysockaddr *addr, char *arg, const unsigned short qtype, const int id, const ednsData *edns, enum protocol proto, const char* file, const int line);
#define FTL_new_query(flags, name, addr, arg, qtype, id, proto) _FTL_new_query(flags, name, addr, arg, qtype, id, proto, __FILE__, __LINE__)
bool _FTL_new_query(const unsigned int flags, const char *name, union mysockaddr *addr, char *arg, const unsigned short qtype, const int id, enum protocol proto, const char* file, const int line);
#define FTL_header_analysis(header4, rcode, server, id) _FTL_header_analysis(header4, rcode, server, id, __FILE__, __LINE__)
void _FTL_header_analysis(const unsigned char header4, const unsigned int rcode, const struct server *server, const int id, const char* file, const int line);

View File

@ -41,14 +41,26 @@
// dnsmasq option: --add-cpe-id=...
#define EDNS0_CPE_ID EDNS0_OPTION_NOMCPEID
void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockaddr *peer, ednsData *edns)
{
int is_sign;
size_t plen;
unsigned char *pheader, *sizep;
static ednsData edns = { 0 };
// Extract additional record A.K.A. pseudoheader
if (!(pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
ednsData *getEDNS(void)
{
if(edns.valid)
{
// Return pointer to ednsData structure and reset it for the
// next query
edns.valid = false;
return &edns;
}
// No valid EDNS data available
return NULL;
}
void FTL_parse_pseudoheaders(unsigned char *pheader, const size_t plen)
{
// Return early if we have no pseudoheader (a.k.a. additional records)
if (!pheader)
return;
// Debug logging
@ -152,6 +164,11 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
if(edns0_version != 0x00)
return;
// Reset EDNS(0) data
memset(&edns, 0, sizeof(ednsData));
edns.ede = -1;
edns.valid = true;
size_t offset; // The header is 11 bytes before the beginning of OPTION-DATA
while ((offset = (p - pheader - 11u)) < rdlen && rdlen < UINT16_MAX)
{
@ -225,8 +242,8 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
}
// Copy data to edns struct
strncpy(edns->client, ipaddr, ADDRSTRLEN);
edns->client[ADDRSTRLEN-1] = '\0';
strncpy(edns.client, ipaddr, ADDRSTRLEN);
edns.client[ADDRSTRLEN-1] = '\0';
// Only set the address as useful when it is not the
// loopback address of the distant machine (127.0.0.0/8 or ::1)
@ -239,7 +256,7 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
}
else
{
edns->client_set = true;
edns.client_set = true;
if(config.debug & DEBUG_EDNS0)
logg("EDNS(0) CLIENT SUBNET: %s/%u - OK (IPv%u)",
ipaddr, source_netmask, family == 1 ? 4 : 6);
@ -292,11 +309,11 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
else if(code == EDNS0_MAC_ADDR_BYTE && optlen == 6)
{
// EDNS(0) MAC address (BYTE format)
memcpy(edns->mac_byte, p, sizeof(edns->mac_byte));
print_mac(edns->mac_text, (unsigned char*)edns->mac_byte, sizeof(edns->mac_byte));
edns->mac_set = true;
memcpy(edns.mac_byte, p, sizeof(edns.mac_byte));
print_mac(edns.mac_text, (unsigned char*)edns.mac_byte, sizeof(edns.mac_byte));
edns.mac_set = true;
if(config.debug & DEBUG_EDNS0)
logg("EDNS(0) MAC address (BYTE format): %s", edns->mac_text);
logg("EDNS(0) MAC address (BYTE format): %s", edns.mac_text);
// Advance working pointer
p += 6;
@ -304,19 +321,19 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
else if(code == EDNS0_MAC_ADDR_TEXT && optlen == 17)
{
// EDNS(0) MAC address (TEXT format)
memcpy(edns->mac_text, p, 17);
edns->mac_text[17] = '\0';
if(sscanf(edns->mac_text, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&edns->mac_byte[0],
&edns->mac_byte[1],
&edns->mac_byte[2],
&edns->mac_byte[3],
&edns->mac_byte[4],
&edns->mac_byte[5]) == 6)
memcpy(edns.mac_text, p, 17);
edns.mac_text[17] = '\0';
if(sscanf(edns.mac_text, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
(unsigned char*)&edns.mac_byte[0],
(unsigned char*)&edns.mac_byte[1],
(unsigned char*)&edns.mac_byte[2],
(unsigned char*)&edns.mac_byte[3],
(unsigned char*)&edns.mac_byte[4],
(unsigned char*)&edns.mac_byte[5]) == 6)
{
edns->mac_set = true;
edns.mac_set = true;
if(config.debug & DEBUG_EDNS0)
logg("EDNS(0) MAC address (TEXT format): %s", edns->mac_text);
logg("EDNS(0) MAC address (TEXT format): %s", edns.mac_text);
}
else if(config.debug & DEBUG_EDNS0)
{
@ -358,7 +375,7 @@ void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockad
else
{
if(config.debug & DEBUG_EDNS0)
logg("EDNS(0):n option %u with length %u", code, optlen);
logg("EDNS(0): option %u with length %u", code, optlen);
// Not implemented, skip this record
// Advance working pointer

View File

@ -11,13 +11,16 @@
#define EDNS0_HEADER
typedef struct {
bool client_set;
bool mac_set;
bool client_set :1;
bool mac_set :1;
bool valid :1;
char client[ADDRSTRLEN];
char mac_byte[6];
char mac_text[18];
int ede;
} ednsData;
void FTL_parse_pseudoheaders(struct dns_header *header, size_t n, union mysockaddr *peer, ednsData *edns);
ednsData *getEDNS(void);
void FTL_parse_pseudoheaders(unsigned char *pheader, const size_t plen);
#endif // EDNS0_HEADER