Skip to content

Commit

Permalink
Merge pull request #288 from kdrenard/kdrenard_ends0_updates
Browse files Browse the repository at this point in the history
EDNS0 parsing fixes and additional EDNS0 indexers.
  • Loading branch information
jelu authored Jul 5, 2023
2 parents 6a94e06 + b5164fe commit f6dab4a
Show file tree
Hide file tree
Showing 26 changed files with 1,613 additions and 51 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dsc_SOURCES = asn_index.c certain_qnames_index.c client_index.c \
ip_version_index.c md_array.c md_array_json_printer.c \
md_array_xml_printer.c msglen_index.c null_index.c opcode_index.c \
parse_conf.c pcap.c qclass_index.c qname_index.c qnamelen_index.c label_count_index.c \
edns_cookie_index.c edns_nsid_index.c edns_ede_index.c edns_ecs_index.c \
qr_aa_bits_index.c qtype_index.c query_classification_index.c rcode_index.c \
rd_bit_index.c server_ip_addr_index.c tc_bit_index.c tld_index.c \
transport_index.c xmalloc.c response_time_index.c tld_list.c \
Expand All @@ -38,6 +39,7 @@ dist_dsc_SOURCES = asn_index.h base64.h certain_qnames_index.h client_index.h \
idn_qname_index.h inX_addr.h ip_direction_index.h ip_proto_index.h \
ip_version_index.h md_array.h msglen_index.h null_index.h opcode_index.h \
parse_conf.h pcap.h qclass_index.h qname_index.h qnamelen_index.h label_count_index.h \
edns_cookie_index.h edns_nsid_index.h edns_ede_index.h edns_ecs_index.h \
qr_aa_bits_index.h qtype_index.h query_classification_index.h rcode_index.h \
rd_bit_index.h server_ip_addr_index.h syslog_debug.h tc_bit_index.h \
tld_index.h transport_index.h xmalloc.h response_time_index.h tld_list.h \
Expand Down
44 changes: 41 additions & 3 deletions src/dns_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "xmalloc.h"
#include "syslog_debug.h"
#include "tld_list.h"
#include "dns_protocol.h"

#include "null_index.h"
#include "qtype_index.h"
Expand All @@ -53,6 +54,10 @@
#include "server_ip_addr_index.h"
#include "qnamelen_index.h"
#include "label_count_index.h"
#include "edns_cookie_index.h"
#include "edns_nsid_index.h"
#include "edns_ede_index.h"
#include "edns_ecs_index.h"
#include "qname_index.h"
#include "msglen_index.h"
#include "certain_qnames_index.h"
Expand Down Expand Up @@ -104,8 +109,24 @@ static indexer indexers[] = {
{ "certain_qnames", 0, certain_qnames_indexer, certain_qnames_iterator },
{ "query_classification", 0, query_classification_indexer, query_classification_iterator },
{ "idn_qname", 0, idn_qname_indexer, idn_qname_iterator },
{ "edns_version", edns_version_init, edns_version_indexer, edns_version_iterator },
{ "edns_bufsiz", edns_bufsiz_init, edns_bufsiz_indexer, edns_bufsiz_iterator },
{ "edns_version", indexer_want_edns, edns_version_indexer, edns_version_iterator },
{ "edns_bufsiz", indexer_want_edns, edns_bufsiz_indexer, edns_bufsiz_iterator },
{ "edns_cookie", indexer_want_edns_options, edns_cookie_indexer, edns_cookie_iterator },
{ "edns_cookie_len", indexer_want_edns_options, edns_cookie_len_indexer, edns_cookie_len_iterator, edns_cookie_len_reset },
{ "edns_cookie_client", indexer_want_edns_options, edns_cookie_client_indexer, edns_cookie_client_iterator, edns_cookie_client_reset },
{ "edns_cookie_server", indexer_want_edns_options, edns_cookie_server_indexer, edns_cookie_server_iterator, edns_cookie_server_reset },
{ "edns_ecs", indexer_want_edns_options, edns_ecs_indexer, edns_ecs_iterator },
{ "edns_ecs_family", indexer_want_edns_options, edns_ecs_family_indexer, edns_ecs_family_iterator, edns_ecs_family_reset },
{ "edns_ecs_source_prefix", indexer_want_edns_options, edns_ecs_source_prefix_indexer, edns_ecs_source_prefix_iterator, edns_ecs_source_prefix_reset },
{ "edns_ecs_scope_prefix", indexer_want_edns_options, edns_ecs_scope_prefix_indexer, edns_ecs_scope_prefix_iterator, edns_ecs_scope_prefix_reset },
{ "edns_ecs_address", indexer_want_edns_options, edns_ecs_address_indexer, edns_ecs_address_iterator, edns_ecs_address_reset },
{ "edns_ede", indexer_want_edns_options, edns_ede_indexer, edns_ede_iterator },
{ "edns_ede_code", indexer_want_edns_options, edns_ede_code_indexer, edns_ede_code_iterator, edns_ede_code_reset },
{ "edns_ede_textlen", indexer_want_edns_options, edns_ede_textlen_indexer, edns_ede_textlen_iterator, edns_ede_textlen_reset },
{ "edns_ede_text", indexer_want_edns_options, edns_ede_text_indexer, edns_ede_text_iterator, edns_ede_text_reset },
{ "edns_nsid", indexer_want_edns_options, edns_nsid_indexer, edns_nsid_iterator },
{ "edns_nsid_len", indexer_want_edns_options, edns_nsid_len_indexer, edns_nsid_len_iterator, edns_nsid_len_reset },
{ "edns_nsid_data", indexer_want_edns_options, edns_nsid_data_indexer, edns_nsid_data_iterator, edns_nsid_data_reset },
{ "do_bit", 0, do_bit_indexer, do_bit_iterator },
{ "rd_bit", 0, rd_bit_indexer, rd_bit_iterator },
{ "tc_bit", 0, tc_bit_indexer, tc_bit_iterator },
Expand Down Expand Up @@ -213,6 +234,11 @@ static int servfail_filter(const dns_message* m, const void* ctx)
return m->rcode == 2;
}

static int edns0_filter(const dns_message* m, const void* ctx)
{
return m->edns.found && m->edns.version == 0;
}

/*
* Helpers
*/
Expand Down Expand Up @@ -406,7 +432,7 @@ const char* dns_message_QnameToNld(const char* qname, int nld)
if (have_tld_list) {
// Use TLD list to find labels that are the "TLD"
const char *lt = 0, *ot = t;
int done = 0;
int done = 0;
while (t > qname) {
t--;
if ('.' == *t) {
Expand Down Expand Up @@ -478,6 +504,7 @@ void dns_message_filters_init(void)
fl = md_array_filter_list_append(fl, md_array_create_filter("chaos-class", chaos_class_filter, 0));
fl = md_array_filter_list_append(fl, md_array_create_filter("priming-query", priming_query_filter, 0));
fl = md_array_filter_list_append(fl, md_array_create_filter("servfail-only", servfail_filter, 0));
fl = md_array_filter_list_append(fl, md_array_create_filter("edns0-only", edns0_filter, 0));
(void)md_array_filter_list_append(fl, md_array_create_filter("authentic-data-only", ad_filter, 0));
}

Expand Down Expand Up @@ -511,3 +538,14 @@ int add_qname_filter(const char* name, const char* pat)
(void)md_array_filter_list_append(fl, md_array_create_filter(name, qname_filter, r));
return 1;
}

void indexer_want_edns(void)
{
dns_protocol_parse_edns = 1;
}

void indexer_want_edns_options(void)
{
dns_protocol_parse_edns = 1;
dns_protocol_parse_edns_options = 1;
}
40 changes: 40 additions & 0 deletions src/dns_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ struct dns_message {
unsigned int DO : 1; /* set if DNSSEC DO bit is set */
unsigned char version; /* version field from OPT RR */
unsigned short bufsiz; /* class field from OPT RR */

// bitmap of found EDNS(0) options
struct {
unsigned int cookie : 1;
unsigned int nsid : 1;
unsigned int ede : 1;
unsigned int ecs : 1;
} option;

// cookie rfc 7873
struct {
const u_char* client; // pointer to 8 byte client part
const u_char* server; // pointer to server part, may be null
unsigned short server_len; // length of server part, if any
} cookie;

// nsid rfc 5001
struct {
const u_char* data; // pointer to nsid payload, may be null
unsigned short len; // length of nsid, if any
} nsid;

// extended error codes rfc 8914
struct {
unsigned short code;
const u_char* text; // pointer to EXTRA-TEXT, may be null
unsigned short len; // length of text, if any
} ede;

// client subnet rfc 7871
struct {
unsigned short family;
unsigned char source_prefix;
unsigned char scope_prefix;
const u_char* address; // pointer to address, may be null
unsigned short len; // length of address, if any
} ecs;
} edns;
};

Expand All @@ -113,6 +150,9 @@ void dns_message_filters_init(void);
void dns_message_indexers_init(void);
int add_qname_filter(const char* name, const char* pat);

void indexer_want_edns(void);
void indexer_want_edns_options(void);

#include <arpa/nameser.h>
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
Expand Down
92 changes: 85 additions & 7 deletions src/dns_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,75 @@ static off_t skip_question(const u_char* buf, int len, off_t offset)
return offset;
}

#define EDNS0_TYPE_NSID 3
#define EDNS0_TYPE_ECS 8
#define EDNS0_TYPE_COOKIE 10
#define EDNS0_TYPE_EXTENDED_ERROR 15

static void process_edns0_options(const u_char* buf, int len, struct dns_message* m)
{
unsigned short edns0_type;
unsigned short edns0_len;
off_t offset = 0;

while (len >= 4) {
edns0_type = nptohs(buf + offset);
edns0_len = nptohs(buf + offset + 2);
if (len < 4 + edns0_len)
break;
switch (edns0_type) {
case EDNS0_TYPE_COOKIE:
if (m->edns.option.cookie)
break;
if (edns0_len == 8) {
m->edns.option.cookie = 1;
m->edns.cookie.client = buf + offset + 4;
} else if (edns0_len >= 16 && edns0_len <= 40) {
m->edns.option.cookie = 1;
m->edns.cookie.client = buf + offset + 4;
m->edns.cookie.server = m->edns.cookie.client + 8;
m->edns.cookie.server_len = edns0_len - 8;
}
break;
case EDNS0_TYPE_NSID:
if (m->edns.option.nsid)
break;
m->edns.option.nsid = 1;
if (edns0_len) {
m->edns.nsid.data = buf + offset + 4;
m->edns.nsid.len = edns0_len;
}
break;
case EDNS0_TYPE_ECS:
if (m->edns.option.ecs || edns0_len < 4)
break;
m->edns.option.ecs = 1;
m->edns.ecs.family = nptohs(buf + offset + 4);
m->edns.ecs.source_prefix = *(buf + offset + 6);
m->edns.ecs.scope_prefix = *(buf + offset + 7);
if (edns0_len > 4) {
m->edns.ecs.address = buf + offset + 8;
m->edns.ecs.len = edns0_len - 4;
}
break;
case EDNS0_TYPE_EXTENDED_ERROR:
if (m->edns.option.ede || edns0_len < 2)
break;
m->edns.option.ede = 1;
m->edns.ede.code = nptohs(buf + offset + 4);
if (edns0_len > 2) {
m->edns.ede.text = buf + offset + 6;
m->edns.ede.len = edns0_len - 2;
}
break;
}
offset += 4 + edns0_len;
len -= 4 + edns0_len;
}
}

int dns_protocol_parse_edns_options = 0;

static off_t grok_additional_for_opt_rr(const u_char* buf, int len, off_t offset, dns_message* m)
{
unsigned short us;
Expand All @@ -225,11 +294,20 @@ static off_t grok_additional_for_opt_rr(const u_char* buf, int len, off_t offset
if (offset + 10 > len)
return 0;
if (nptohs(buf + offset) == T_OPT && !m->edns.found) {
m->edns.found = 1;
m->edns.bufsiz = nptohs(buf + offset + 2);
memcpy(&m->edns.version, buf + offset + 5, 1);
us = nptohs(buf + offset + 6);
m->edns.DO = (us >> 15) & 0x01; /* RFC 3225 */
m->edns.found = 1;
m->edns.bufsiz = nptohs(buf + offset + 2);
m->edns.version = *(buf + offset + 5);
us = nptohs(buf + offset + 6);
m->edns.DO = (us >> 15) & 0x01; /* RFC 3225 */

us = nptohs(buf + offset + 8); // rd len
offset += 10;
if (offset + us > len)
return 0;
if (dns_protocol_parse_edns_options && !m->edns.version && us > 0)
process_edns0_options(buf + offset, us, m);
offset += us;
return offset;
}
}
/* get rdlength */
Expand All @@ -255,7 +333,7 @@ static off_t skip_rr(const u_char* buf, int len, off_t offset)
return offset;
}

int dns_protocol_parse_edns0 = 0;
int dns_protocol_parse_edns = 0;

int dns_protocol_handler(const u_char* buf, int len, void* udata)
{
Expand Down Expand Up @@ -306,7 +384,7 @@ int dns_protocol_handler(const u_char* buf, int len, void* udata)
offset = new_offset;
qdcount--;
}
if (!dns_protocol_parse_edns0)
if (!dns_protocol_parse_edns)
goto handle_m;
assert(offset <= len);

Expand Down
3 changes: 2 additions & 1 deletion src/dns_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@

#include <sys/types.h>

extern int dns_protocol_parse_edns0;
extern int dns_protocol_parse_edns;
extern int dns_protocol_parse_edns_options;

int dns_protocol_handler(const u_char* buf, int len, void* udata);

Expand Down
51 changes: 51 additions & 0 deletions src/dsc.conf.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,54 @@ EDNS Version 0 is documented in RFC 2671.
\fBedns_bufsiz\fR
The EDNS buffer size per 512 chunks (0-511, 512-1023 etc).
.TP
\fBedns_cookie\fR
Indicates whether or not a EDNS(0) Cookie (RFC7873) was present with "yes" or "no".
.TP
\fBedns_cookie_len\fR
The combined length of the EDNS(0) client and server cookies.
.TP
\fBedns_cookie_client\fR
The EDNS(0) Client Cookie bytes as a hexadecimal string.
.TP
\fBedns_cookie_server\fR
The EDNS(0) Server Cookie bytes as a hexadecimal string.
.TP
\fBedns_ecs\fR
Indicates whether or not a EDNS(0) Client Subnet (RFC7871) was present with "yes" or "no".
.TP
\fBedns_ecs_family\fR
The EDNS(0) Client Subnet address family.
.TP
\fBedns_ecs_source_prefix\fR
The EDNS(0) Client Subnet source prefix-length.
.TP
\fBedns_ecs_scope_prefix\fR
The EDNS(0) Client Subnet scope prefix-length.
.TP
\fBedns_ecs_address\fR
The EDNS(0) Client Subnet address bytes as a hexadecimal string.
.TP
\fBedns_ede\fR
Indicates whether or not a EDNS(0) Extended DNS Errors (RFC8914) was present with "yes" or "no".
.TP
\fBedns_ede_code\fR
The EDNS(0) Extended DNS Errors code.
.TP
\fBedns_ede_textlen\fR
The length of the EDNS(0) Extended DNS Errors extra-text.
.TP
\fBedns_ede_text\fR
The EDNS(0) Extended DNS Errors extra-text.
.TP
\fBedns_nsid\fR
Indicates whether or not a EDNS(0) DNS Name Server Identifier (RFC5001) was present with "yes" or "no".
.TP
\fBedns_nsid_len\fR
The length of the EDNS(0) DNS Name Server Identifier (NSID).
.TP
\fBedns_nsid_data\fR
The EDNS(0) DNS Name Server Identifier (NSID) bytes as a hexadecimal string.
.TP
\fBidn_qname\fR
This indexer has only two values: 0 or 1.
It returns 1 when the first QNAME in the DNS message question section
Expand Down Expand Up @@ -706,6 +754,9 @@ Count only SERVFAIL responses.
.TP
\fBauthentic-data-only\fR
Count only DNS messages with the AD bit is set.
.TP
\fBedns0-only\fR
Count only DNS messages with EDNS(0) options.
.SH "QNAME FILTERS"
Defines a custom QNAME-based filter for DNS messages.
If you refer to this named filter on a dataset line, then only queries
Expand Down
6 changes: 0 additions & 6 deletions src/edns_bufsiz_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
#include "config.h"

#include "edns_bufsiz_index.h"
#include "dns_protocol.h"

void edns_bufsiz_init(void)
{
dns_protocol_parse_edns0 = 1;
}

int edns_bufsiz_max = 0;

Expand Down
1 change: 0 additions & 1 deletion src/edns_bufsiz_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

#include "dns_message.h"

void edns_bufsiz_init(void);
int edns_bufsiz_indexer(const dns_message*);
int edns_bufsiz_iterator(const char** label);

Expand Down
Loading

0 comments on commit f6dab4a

Please sign in to comment.