Skip to content

Commit

Permalink
Buf overflow check, move OPT RR parsing, rework EDNS0 ECS
Browse files Browse the repository at this point in the history
- Add buffer overflow check for `get_ushort()`
- Add `get_uint32()`
- Move OPT RR code to `parse_opt_rr()`, call it after each successful
  additional record parsing
- Parse EDNS0 options and save first Client Subnet (ECS) found
- Corrected fields documentation
  • Loading branch information
jelu committed Jun 7, 2017
1 parent d38fffc commit 358b9af
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 87 deletions.
12 changes: 10 additions & 2 deletions FIELDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ the dns table, presented as JSON identifiers.
{ "name": "src_addr","type": "text" },
{ "name": "dst_addr","type": "text" },
{ "name": "protocol","type": "int" },
{ "name": "ip_ttl","type": "int" },
{ "name": "fragments","type": "int" },
{ "name": "qname","type": "text" },
{ "name": "aname","type": "text" },
{ "name": "msg_id","type": "int" },
{ "name": "msg_size","type": "int" },
{ "name": "opcode","type": "int" },
{ "name": "rcode","type": "int" },
{ "name": "extended_rcode","type": "int" },
{ "name": "version","type": "int" },
{ "name": "edns_version","type": "int" },
{ "name": "z","type": "int" },
{ "name": "udp_size","type": "int" },
{ "name": "qd_count","type": "int" },
Expand All @@ -41,7 +44,12 @@ the dns table, presented as JSON identifiers.
{ "name": "ad","type": "bool" },
{ "name": "do","type": "bool" },
{ "name": "edns0","type": "bool" },
{ "name": "qr","type": "bool" }
{ "name": "qr","type": "bool" },
{ "name": "edns0_esc","type": "bool" },
{ "name": "edns0_esc_family","type": "int" },
{ "name": "edns0_esc_source","type": "int" },
{ "name": "edns0_esc_scope","type": "int" },
{ "name": "edns0_esc_address","type": "text" }
}
]
```
49 changes: 37 additions & 12 deletions src/dns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ 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 All @@ -83,6 +81,12 @@ void Parse_dns::add_packet_columns()
add_packet_column("do", "", Coltype::_bool, COLUMN_DO);
add_packet_column("edns0", "", Coltype::_bool, COLUMN_EDNS0);
add_packet_column("qr", "", Coltype::_bool, COLUMN_QR);

add_packet_column("edns0_esc", "", Coltype::_bool, COLUMN_EDNS0_ECS);
add_packet_column("edns0_esc_family", "", Coltype::_int, COLUMN_EDNS0_ECS_FAMILY);
add_packet_column("edns0_esc_source", "", Coltype::_int, COLUMN_EDNS0_ECS_SOURCE);
add_packet_column("edns0_esc_scope", "", Coltype::_int, COLUMN_EDNS0_ECS_SCOPE);
add_packet_column("edns0_esc_address", "", Coltype::_text, COLUMN_EDNS0_ECS_ADDRESS);
}

void Parse_dns::add_lookup_tables()
Expand Down Expand Up @@ -191,7 +195,6 @@ 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 @@ -214,7 +217,12 @@ 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");

acc_edns0_ecs = table->get_accessor<bool_column>("edns0_esc");
acc_edns0_ecs_family = table->get_accessor<int_column>("edns0_esc_family");
acc_edns0_ecs_source = table->get_accessor<int_column>("edns0_esc_source");
acc_edns0_ecs_scope = table->get_accessor<int_column>("edns0_esc_scope");
acc_edns0_ecs_address = table->get_accessor<text_column>("edns0_esc_address");
}

Packet::ParseResult Parse_dns::parse(Packet& packet, const std::vector<int>& columns, Row& destination_row, bool sample)
Expand Down Expand Up @@ -349,14 +357,6 @@ 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 All @@ -372,6 +372,31 @@ Packet::ParseResult Parse_dns::parse(Packet& packet, const std::vector<int>& col
case COLUMN_ATTL:
acc_attl.value(r) = header.ancount ? message.m_answer[0].ttl : 0;
break;

case COLUMN_EDNS0_ECS:
acc_edns0_ecs.value(r) = message.m_edns0_ecs ? 1 : 0;
break;

case COLUMN_EDNS0_ECS_FAMILY:
acc_edns0_ecs_family.value(r) = message.m_edns0_ecs_family;
break;

case COLUMN_EDNS0_ECS_SOURCE:
acc_edns0_ecs_source.value(r) = message.m_edns0_ecs_source;
break;

case COLUMN_EDNS0_ECS_SCOPE:
acc_edns0_ecs_scope.value(r) = message.m_edns0_ecs_scope;
break;

case COLUMN_EDNS0_ECS_ADDRESS:
if (message.m_edns0_ecs_addr_set && message.m_edns0_ecs_family == 1)
acc_edns0_ecs_address.value(r) = v4_addr2str(message.m_edns0_ecs_addr);
else if (message.m_edns0_ecs_addr_set && message.m_edns0_ecs_family == 2)
acc_edns0_ecs_address.value(r) = v6_addr2str(message.m_edns0_ecs_addr);
else
acc_edns0_ecs_address.value(r) = RefCountString::construct("");
break;
}
}

Expand Down
149 changes: 79 additions & 70 deletions src/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@ 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 @@ -153,18 +151,6 @@ 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 @@ -186,9 +172,12 @@ 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];
bool m_edns0_ecs;
int m_edns0_ecs_family;
int m_edns0_ecs_source;
int m_edns0_ecs_scope;
in6addr_t m_edns0_ecs_addr;
bool m_edns0_ecs_addr_set;

DNSMessage(unsigned char* data, int len, IP_header& head)
: m_ip_header(head)
Expand All @@ -203,8 +192,11 @@ class DNSMessage {
m_edns_version = 0;
m_z = 0;
m_udp_size = 0;
m_edns_opcode = 0;
m_ecs = false;
m_edns0_ecs = false;
m_edns0_ecs_family = 0;
m_edns0_ecs_source = 0;
m_edns0_ecs_scope = 0;
m_edns0_ecs_addr_set = false;

parse();
}
Expand Down Expand Up @@ -244,6 +236,56 @@ class DNSMessage {
out[p++] = 0;
return offs;
}
void parse_opt_rr() {
if (m_opt_rr) {
if (!m_edns0) {
m_edns0 = true;
unsigned long ttl = m_opt_rr->ttl;
m_do = (ttl >> 15) & 1;
m_extended_rcode = ttl >> 24;
m_edns_version = (ttl >> 16) & 0xff;
m_z = ttl & 0x7fff;
m_udp_size = m_opt_rr->rr_class;
}
if ((m_opt_rr->ttl >> 16) & 0xff == 0) {
// Parse this OPT RR that is EDNS0
int rdlen = m_opt_rr->rdlength,
offs = m_opt_rr->doffs,
opcode = 0,
oplen = 0;

while (rdlen > 3) {
// Minimum op code and length
opcode = get_ushort(offs);
oplen = get_ushort(offs + 2);
offs += 4;
rdlen -= 4;

if (rdlen < oplen)
break;

if (opcode == 8 && !m_edns0_ecs && oplen > 3) {
// ECS - Client Subnet - RFC7871
m_edns0_ecs = true;
m_edns0_ecs_family = get_ushort(offs);
m_edns0_ecs_source = get_ubyte(offs + 2);
m_edns0_ecs_scope = get_ubyte(offs + 3);
if (m_edns0_ecs_family == 1 && oplen == 8) {
m_edns0_ecs_addr.__in6_u.__u6_addr32[3] = get_uint32(offs + 4);
m_edns0_ecs_addr_set = true;
}
else if (m_edns0_ecs_family == 2 && oplen == 20) {
m_edns0_ecs_addr.__in6_u.__u6_addr32[3] = get_uint32(offs + 4);
m_edns0_ecs_addr.__in6_u.__u6_addr32[2] = get_uint32(offs + 8);
m_edns0_ecs_addr.__in6_u.__u6_addr32[1] = get_uint32(offs + 12);
m_edns0_ecs_addr.__in6_u.__u6_addr32[0] = get_uint32(offs + 16);
m_edns0_ecs_addr_set = true;
}
}
}
}
}
}
void parse()
{
m_header.parse(*this);
Expand Down Expand Up @@ -288,51 +330,10 @@ class DNSMessage {
m_error = offs;
return;
}

if (m_opt_rr && !m_edns0) {
m_edns0 = true;
unsigned long ttl = m_opt_rr->ttl;
m_do = (ttl >> 15) & 1;
m_extended_rcode = ttl >> 24;
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);
}
}
}
parse_opt_rr();
}
if (offs > m_length)
m_error = offs;

if (m_opt_rr && !m_edns0) {
m_edns0 = true;
unsigned long ttl = m_opt_rr->ttl;
m_do = (ttl >> 15) & 1;
m_extended_rcode = ttl >> 24;
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);
}
}
}
}

unsigned int get_ubyte(int offs)
Expand All @@ -344,10 +345,16 @@ class DNSMessage {
// returns 16 bit number at byte offset offs
unsigned int get_ushort(int offs)
{
if (offs >= m_length)
if ((offs + 1) >= m_length)
return 0;
return (int(m_data[offs]) << 8) | int(m_data[offs + 1]);
}
uint32_t get_uint32(int offs)
{
if ((offs + 3) >= m_length)
return 0;
return (uint32_t(m_data[offs]) << 24) | (uint32_t(m_data[offs + 1]) << 16) | (uint32_t(m_data[offs + 2]) << 8) | uint32_t(m_data[offs + 3]);
}
bool get_bit(int offs, int bit)
{
if (offs >= m_length)
Expand All @@ -360,10 +367,6 @@ 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 @@ -379,8 +382,6 @@ 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 All @@ -399,6 +400,11 @@ class Parse_dns : public Packet_handler {
COLUMN_DO,
COLUMN_EDNS0,
COLUMN_QR,
COLUMN_EDNS0_ECS,
COLUMN_EDNS0_ECS_FAMILY,
COLUMN_EDNS0_ECS_SOURCE,
COLUMN_EDNS0_ECS_SCOPE,
COLUMN_EDNS0_ECS_ADDRESS,
};

Parse_dns();
Expand Down Expand Up @@ -427,7 +433,6 @@ 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 @@ -437,6 +442,9 @@ class Parse_dns : public Packet_handler {
Int_accessor acc_atype;
Int_accessor acc_aclass;
Int_accessor acc_attl;
Int_accessor acc_edns0_ecs_family;
Int_accessor acc_edns0_ecs_source;
Int_accessor acc_edns0_ecs_scope;
Bool_accessor acc_qr;
Bool_accessor acc_aa;
Bool_accessor acc_tc;
Expand All @@ -446,11 +454,12 @@ class Parse_dns : public Packet_handler {
Bool_accessor acc_ad;
Bool_accessor acc_do;
Bool_accessor acc_edns0;
Text_accessor acc_ecs_addr;
Bool_accessor acc_edns0_ecs;
Text_accessor acc_qname;
Text_accessor acc_aname;
Text_accessor acc_src_addr;
Text_accessor acc_dst_addr;
Text_accessor acc_edns0_ecs_address;
};

} // namespace packetq
Expand Down
10 changes: 7 additions & 3 deletions src/packetq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,13 @@ static void usage(char* argv0, bool longversion)
" ad\n"
" do\n"
" edns0\n"
" edns_opcode\n"
" ecs_addr\n"
" qr\n");
" qr\n"
" edns0_esc\n"
" edns0_esc_family\n"
" edns0_esc_source\n"
" edns0_esc_scope\n"
" edns0_esc_address\n"
);
}

#ifdef WIN32
Expand Down

0 comments on commit 358b9af

Please sign in to comment.