Skip to content

Commit

Permalink
Add EDNS option codes and EDNS Client Subnet (ECS) support
Browse files Browse the repository at this point in the history
  • Loading branch information
stirnim authored and jelu committed Jun 7, 2017
1 parent 02f481a commit d38fffc
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/dns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ void Parse_dns::add_packet_columns()
add_packet_column("edns_version", "", Coltype::_int, COLUMN_EDNS_VERSION);
add_packet_column("z", "", Coltype::_int, COLUMN_Z);
add_packet_column("udp_size", "", Coltype::_int, COLUMN_UDP_SIZE);
add_packet_column("edns_opcode", "", Coltype::_int, COLUMN_EDNS_OPCODE);
add_packet_column("ecs_addr", "", Coltype::_text, COLUMN_ECS_ADDR);
add_packet_column("qd_count", "", Coltype::_int, COLUMN_QD_COUNT);
add_packet_column("an_count", "", Coltype::_int, COLUMN_AN_COUNT);
add_packet_column("ns_count", "", Coltype::_int, COLUMN_NS_COUNT);
Expand Down Expand Up @@ -189,6 +191,7 @@ void Parse_dns::on_table_created(Table* table, const std::vector<int>& columns)
acc_edns_version = table->get_accessor<int_column>("edns_version");
acc_z = table->get_accessor<int_column>("z");
acc_udp_size = table->get_accessor<int_column>("udp_size");
acc_edns_opcode = table->get_accessor<int_column>("edns_opcode");
acc_qd_count = table->get_accessor<int_column>("qd_count");
acc_an_count = table->get_accessor<int_column>("an_count");
acc_ns_count = table->get_accessor<int_column>("ns_count");
Expand All @@ -211,6 +214,7 @@ void Parse_dns::on_table_created(Table* table, const std::vector<int>& columns)

acc_qname = table->get_accessor<text_column>("qname");
acc_aname = table->get_accessor<text_column>("aname");
acc_ecs_addr = table->get_accessor<text_column>("ecs_addr");
}

Packet::ParseResult Parse_dns::parse(Packet& packet, const std::vector<int>& columns, Row& destination_row, bool sample)
Expand Down Expand Up @@ -345,6 +349,14 @@ Packet::ParseResult Parse_dns::parse(Packet& packet, const std::vector<int>& col
acc_udp_size.value(r) = message.m_edns0 ? message.m_udp_size : 0;
break;

case COLUMN_EDNS_OPCODE:
acc_edns_opcode.value(r) = message.m_edns_opcode ? message.m_edns_opcode : 0;
break;

case COLUMN_ECS_ADDR:
acc_ecs_addr.value(r) = message.m_ecs ? RefCountString::construct(message.m_ecs_addr) : RefCountString::construct("");
break;

case COLUMN_ANAME:
acc_aname.value(r) = header.ancount ? RefCountString::construct(message.m_answer[0].name) : RefCountString::construct("");
break;
Expand Down
49 changes: 49 additions & 0 deletions src/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class DNSMessage {
unsigned int ttl;
int rdlength;
int doffs;
unsigned int opt_code_length;
char ecs_addr[0x200];

int parse(DNSMessage& m, int offs)
{
Expand All @@ -151,6 +153,18 @@ class DNSMessage {
rdlength = m.get_ushort(offs);
offs += 2;
doffs = offs;
if (type == 41 && rdlength >= 4)
{
opt_code_length = m.get_ushort(offs) << 16;
opt_code_length |= m.get_ushort(offs + 2);
// We only support EDNS ECS, this copies address field
// and rest of opt_rdata. I.e. it skips family, and
// prefix-length fields
if (rdlength >= 8)
{
memcpy(ecs_addr, m.m_data + offs + 4, rdlength - 4);
}
}
offs += rdlength;
return offs;
}
Expand All @@ -172,6 +186,9 @@ class DNSMessage {
int m_edns_version;
int m_z;
int m_udp_size;
int m_edns_opcode;
bool m_ecs;
char m_ecs_addr[16];

DNSMessage(unsigned char* data, int len, IP_header& head)
: m_ip_header(head)
Expand All @@ -186,6 +203,8 @@ class DNSMessage {
m_edns_version = 0;
m_z = 0;
m_udp_size = 0;
m_edns_opcode = 0;
m_ecs = false;

parse();
}
Expand Down Expand Up @@ -278,6 +297,17 @@ class DNSMessage {
m_edns_version = (ttl >> 16) & 0xff;
m_z = ttl & 0x7fff;
m_udp_size = m_opt_rr->rr_class;
if (m_opt_rr->rdlength >= 4)
{
m_edns_opcode = (m_opt_rr->opt_code_length >> 16);
// m_edns_oplength = (m_opt_rr->opt_code_length & 0xffff);
// only supports ECS for IPv4 addresses
if (m_edns_opcode == 8)
{
m_ecs = true;
set_ecs_addr((unsigned char*)m_opt_rr->ecs_addr + 4);
}
}
}
}
if (offs > m_length)
Expand All @@ -291,6 +321,17 @@ class DNSMessage {
m_edns_version = (ttl >> 16) & 0xff;
m_z = ttl & 0x7fff;
m_udp_size = m_opt_rr->rr_class;
if (m_opt_rr->rdlength >= 4)
{
m_edns_opcode = (m_opt_rr->opt_code_length >> 16);
// m_edns_optlength = (m_opt_rr->opt_code_length & 0xffff);
// only supports ECS for IPv4 addresses
if (m_edns_opcode == 8)
{
m_ecs = true;
set_ecs_addr((unsigned char*)m_opt_rr->ecs_addr + 4);
}
}
}
}

Expand Down Expand Up @@ -319,6 +360,10 @@ class DNSMessage {
return 0;
return ((get_ushort(offs) << bit) & 0xffff) >> (16 - bits);
}
void set_ecs_addr(unsigned char* buf)
{
snprintf(m_ecs_addr, sizeof(m_ecs_addr), "%u.%u.%u.0", buf[0], buf[1], buf[2]);
}
};

class Parse_dns : public Packet_handler {
Expand All @@ -334,6 +379,8 @@ class Parse_dns : public Packet_handler {
COLUMN_EDNS_VERSION,
COLUMN_Z,
COLUMN_UDP_SIZE,
COLUMN_EDNS_OPCODE,
COLUMN_ECS_ADDR,
COLUMN_QD_COUNT,
COLUMN_AN_COUNT,
COLUMN_NS_COUNT,
Expand Down Expand Up @@ -380,6 +427,7 @@ class Parse_dns : public Packet_handler {
Int_accessor acc_edns_version;
Int_accessor acc_z;
Int_accessor acc_udp_size;
Int_accessor acc_edns_opcode;
Int_accessor acc_qd_count;
Int_accessor acc_an_count;
Int_accessor acc_ns_count;
Expand All @@ -398,6 +446,7 @@ class Parse_dns : public Packet_handler {
Bool_accessor acc_ad;
Bool_accessor acc_do;
Bool_accessor acc_edns0;
Text_accessor acc_ecs_addr;
Text_accessor acc_qname;
Text_accessor acc_aname;
Text_accessor acc_src_addr;
Expand Down
2 changes: 2 additions & 0 deletions src/packetq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ static void usage(char* argv0, bool longversion)
" ad\n"
" do\n"
" edns0\n"
" edns_opcode\n"
" ecs_addr\n"
" qr\n");
}

Expand Down

0 comments on commit d38fffc

Please sign in to comment.