1 /*
2  * Copyright (c) 2017, OARC, Inc.
3  * Copyright (c) 2011-2017, IIS - The Internet Foundation in Sweden
4  * All rights reserved.
5  *
6  * This file is part of PacketQ.
7  *
8  * PacketQ is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * PacketQ is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with PacketQ.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "dns.h"
23 #include "output.h"
24 #include "packet_handler.h"
25 #include "packetq.h"
26 #include "tcp.h"
27 
28 #include <cctype>
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 namespace packetq {
33 
34 char visible_char_map[256];
35 
fill_in_visible_char_map()36 void fill_in_visible_char_map()
37 {
38     for (int i = 0; i < 256; ++i) {
39         visible_char_map[i] = isgraph(i) ? i : '$';
40     }
41 }
42 
Parse_dns()43 Parse_dns::Parse_dns()
44 {
45     fill_in_visible_char_map();
46 
47     table_name = "dns";
48 
49     add_packet_columns();
50     add_lookup_tables();
51 }
52 
add_packet_columns()53 void Parse_dns::add_packet_columns()
54 {
55     m_ip_helper.add_packet_columns(*this);
56 
57     add_packet_column("qname", "", Coltype::_text, COLUMN_QNAME);
58     add_packet_column("aname", "", Coltype::_text, COLUMN_ANAME);
59     add_packet_column("msg_id", "", Coltype::_int, COLUMN_MSG_ID);
60     add_packet_column("msg_size", "", Coltype::_int, COLUMN_MSG_SIZE);
61     add_packet_column("opcode", "", Coltype::_int, COLUMN_OPCODE);
62     add_packet_column("rcode", "", Coltype::_int, COLUMN_RCODE);
63     add_packet_column("extended_rcode", "", Coltype::_int, COLUMN_EXTENDED_RCODE);
64     add_packet_column("edns_version", "", Coltype::_int, COLUMN_EDNS_VERSION);
65     add_packet_column("z", "", Coltype::_int, COLUMN_Z);
66     add_packet_column("udp_size", "", Coltype::_int, COLUMN_UDP_SIZE);
67     add_packet_column("qd_count", "", Coltype::_int, COLUMN_QD_COUNT);
68     add_packet_column("an_count", "", Coltype::_int, COLUMN_AN_COUNT);
69     add_packet_column("ns_count", "", Coltype::_int, COLUMN_NS_COUNT);
70     add_packet_column("ar_count", "", Coltype::_int, COLUMN_AR_COUNT);
71     add_packet_column("qtype", "", Coltype::_int, COLUMN_QTYPE);
72     add_packet_column("qclass", "", Coltype::_int, COLUMN_QCLASS);
73     add_packet_column("atype", "", Coltype::_int, COLUMN_ATYPE);
74     add_packet_column("aclass", "", Coltype::_int, COLUMN_ACLASS);
75     add_packet_column("attl", "", Coltype::_int, COLUMN_ATTL);
76     add_packet_column("aa", "", Coltype::_bool, COLUMN_AA);
77     add_packet_column("tc", "", Coltype::_bool, COLUMN_TC);
78     add_packet_column("rd", "", Coltype::_bool, COLUMN_RD);
79     add_packet_column("cd", "", Coltype::_bool, COLUMN_CD);
80     add_packet_column("ra", "", Coltype::_bool, COLUMN_RA);
81     add_packet_column("ad", "", Coltype::_bool, COLUMN_AD);
82     add_packet_column("do", "", Coltype::_bool, COLUMN_DO);
83     add_packet_column("edns0", "", Coltype::_bool, COLUMN_EDNS0);
84     add_packet_column("qr", "", Coltype::_bool, COLUMN_QR);
85 
86     add_packet_column("edns0_ecs", "", Coltype::_bool, COLUMN_EDNS0_ECS);
87     add_packet_column("edns0_ecs_family", "", Coltype::_int, COLUMN_EDNS0_ECS_FAMILY);
88     add_packet_column("edns0_ecs_source", "", Coltype::_int, COLUMN_EDNS0_ECS_SOURCE);
89     add_packet_column("edns0_ecs_scope", "", Coltype::_int, COLUMN_EDNS0_ECS_SCOPE);
90     add_packet_column("edns0_ecs_address", "", Coltype::_text, COLUMN_EDNS0_ECS_ADDRESS);
91 }
92 
add_lookup_tables()93 void Parse_dns::add_lookup_tables()
94 {
95     g_db.add_lut("qtype", 1, "A");
96     g_db.add_lut("qtype", 2, "NS");
97     g_db.add_lut("qtype", 3, "MD");
98     g_db.add_lut("qtype", 4, "MF");
99     g_db.add_lut("qtype", 5, "CNAME");
100     g_db.add_lut("qtype", 6, "SOA");
101     g_db.add_lut("qtype", 7, "MB");
102     g_db.add_lut("qtype", 8, "MG");
103     g_db.add_lut("qtype", 9, "MR");
104     g_db.add_lut("qtype", 10, "NULL");
105     g_db.add_lut("qtype", 11, "WKS");
106     g_db.add_lut("qtype", 12, "PTR");
107     g_db.add_lut("qtype", 13, "HINFO");
108     g_db.add_lut("qtype", 14, "MINFO");
109     g_db.add_lut("qtype", 15, "MX");
110     g_db.add_lut("qtype", 16, "TXT");
111     g_db.add_lut("qtype", 17, "RP");
112     g_db.add_lut("qtype", 18, "AFSDB");
113     g_db.add_lut("qtype", 19, "X25");
114     g_db.add_lut("qtype", 20, "ISDN");
115     g_db.add_lut("qtype", 21, "RT");
116     g_db.add_lut("qtype", 22, "NSAP");
117     g_db.add_lut("qtype", 23, "NSAP-PTR");
118     g_db.add_lut("qtype", 24, "SIG");
119     g_db.add_lut("qtype", 25, "KEY");
120     g_db.add_lut("qtype", 26, "PX");
121     g_db.add_lut("qtype", 27, "GPOS");
122     g_db.add_lut("qtype", 28, "AAAA");
123     g_db.add_lut("qtype", 29, "LOC");
124     g_db.add_lut("qtype", 30, "NXT");
125     g_db.add_lut("qtype", 31, "EID");
126     g_db.add_lut("qtype", 32, "NIMLOC");
127     g_db.add_lut("qtype", 33, "SRV");
128     g_db.add_lut("qtype", 34, "ATMA");
129     g_db.add_lut("qtype", 35, "NAPTR");
130     g_db.add_lut("qtype", 36, "KX");
131     g_db.add_lut("qtype", 37, "CERT");
132     g_db.add_lut("qtype", 38, "A6");
133     g_db.add_lut("qtype", 39, "DNAME");
134     g_db.add_lut("qtype", 40, "SINK");
135     g_db.add_lut("qtype", 41, "OPT");
136     g_db.add_lut("qtype", 42, "APL");
137     g_db.add_lut("qtype", 43, "DS");
138     g_db.add_lut("qtype", 44, "SSHFP");
139     g_db.add_lut("qtype", 45, "IPSECKEY");
140     g_db.add_lut("qtype", 46, "RRSIG");
141     g_db.add_lut("qtype", 47, "NSEC");
142     g_db.add_lut("qtype", 48, "DNSKEY");
143     g_db.add_lut("qtype", 49, "DHCID");
144     g_db.add_lut("qtype", 50, "NSEC3");
145     g_db.add_lut("qtype", 51, "NSEC3PARAM");
146     g_db.add_lut("qtype", 55, "HIP");
147     g_db.add_lut("qtype", 56, "NINFO");
148     g_db.add_lut("qtype", 57, "RKEY");
149     g_db.add_lut("qtype", 58, "TALINK");
150     g_db.add_lut("qtype", 99, "SPF");
151     g_db.add_lut("qtype", 100, "UINFO");
152     g_db.add_lut("qtype", 101, "UID");
153     g_db.add_lut("qtype", 102, "GID");
154     g_db.add_lut("qtype", 103, "UNSPEC");
155     g_db.add_lut("qtype", 249, "TKEY");
156     g_db.add_lut("qtype", 250, "TSIG");
157     g_db.add_lut("qtype", 251, "IXFR");
158     g_db.add_lut("qtype", 252, "AXFR");
159     g_db.add_lut("qtype", 253, "MAILB");
160     g_db.add_lut("qtype", 254, "MAILA");
161     g_db.add_lut("qtype", 255, "*");
162     g_db.add_lut("qtype", 256, "URI");
163     g_db.add_lut("qtype", 32768, "TA");
164     g_db.add_lut("qtype", 32769, "DLV");
165 
166     g_db.add_lut("rcode", 0, "NoError");
167     g_db.add_lut("rcode", 1, "FormErr");
168     g_db.add_lut("rcode", 2, "ServFail");
169     g_db.add_lut("rcode", 3, "NXDomain");
170     g_db.add_lut("rcode", 4, "NotImp");
171     g_db.add_lut("rcode", 5, "Refused");
172     g_db.add_lut("rcode", 6, "YXDomain");
173     g_db.add_lut("rcode", 7, "YXRRSet");
174     g_db.add_lut("rcode", 8, "NXRRSet");
175     g_db.add_lut("rcode", 9, "NotAuth");
176     g_db.add_lut("rcode", 10, "NotZone");
177     g_db.add_lut("rcode", 16, "BADVERS");
178     g_db.add_lut("rcode", 16, "BADSIG");
179     g_db.add_lut("rcode", 17, "BADKEY");
180     g_db.add_lut("rcode", 18, "BADTIME");
181     g_db.add_lut("rcode", 19, "BADMODE");
182     g_db.add_lut("rcode", 20, "BADNAME");
183     g_db.add_lut("rcode", 21, "BADALG");
184     g_db.add_lut("rcode", 22, "BADTRUNC");
185 }
186 
on_table_created(Table * table,const std::vector<int> & columns)187 void Parse_dns::on_table_created(Table* table, const std::vector<int>& columns)
188 {
189     m_ip_helper.on_table_created(table, columns);
190 
191     acc_msg_id         = table->get_accessor<int_column>("msg_id");
192     acc_msg_size       = table->get_accessor<int_column>("msg_size");
193     acc_opcode         = table->get_accessor<int_column>("opcode");
194     acc_rcode          = table->get_accessor<int_column>("rcode");
195     acc_extended_rcode = table->get_accessor<int_column>("extended_rcode");
196     acc_edns_version   = table->get_accessor<int_column>("edns_version");
197     acc_z              = table->get_accessor<int_column>("z");
198     acc_udp_size       = table->get_accessor<int_column>("udp_size");
199     acc_qd_count       = table->get_accessor<int_column>("qd_count");
200     acc_an_count       = table->get_accessor<int_column>("an_count");
201     acc_ns_count       = table->get_accessor<int_column>("ns_count");
202     acc_ar_count       = table->get_accessor<int_column>("ar_count");
203     acc_qtype          = table->get_accessor<int_column>("qtype");
204     acc_qclass         = table->get_accessor<int_column>("qclass");
205     acc_atype          = table->get_accessor<int_column>("atype");
206     acc_aclass         = table->get_accessor<int_column>("aclass");
207     acc_attl           = table->get_accessor<int_column>("attl");
208 
209     acc_qr    = table->get_accessor<bool_column>("qr");
210     acc_aa    = table->get_accessor<bool_column>("aa");
211     acc_tc    = table->get_accessor<bool_column>("tc");
212     acc_rd    = table->get_accessor<bool_column>("rd");
213     acc_cd    = table->get_accessor<bool_column>("cd");
214     acc_ra    = table->get_accessor<bool_column>("ra");
215     acc_ad    = table->get_accessor<bool_column>("ad");
216     acc_do    = table->get_accessor<bool_column>("do");
217     acc_edns0 = table->get_accessor<bool_column>("edns0");
218 
219     acc_qname = table->get_accessor<text_column>("qname");
220     acc_aname = table->get_accessor<text_column>("aname");
221 
222     acc_edns0_ecs         = table->get_accessor<bool_column>("edns0_ecs");
223     acc_edns0_ecs_family  = table->get_accessor<int_column>("edns0_ecs_family");
224     acc_edns0_ecs_source  = table->get_accessor<int_column>("edns0_ecs_source");
225     acc_edns0_ecs_scope   = table->get_accessor<int_column>("edns0_ecs_scope");
226     acc_edns0_ecs_address = table->get_accessor<text_column>("edns0_ecs_address");
227 }
228 
parse(Packet & packet,const std::vector<int> & columns,Row & destination_row,bool sample)229 Packet::ParseResult Parse_dns::parse(Packet& packet, const std::vector<int>& columns, Row& destination_row, bool sample)
230 {
231     if (not(packet.m_len >= 12 && (packet.m_ip_header.proto == IPPROTO_UDP || packet.m_ip_header.proto == IPPROTO_TCP)))
232         return Packet::ERROR;
233 
234     if (!sample)
235         return Packet::NOT_SAMPLED;
236 
237     unsigned char* ddata   = packet.m_data;
238     int            dlength = packet.m_len;
239 
240     if (packet.m_ip_header.proto == IPPROTO_TCP) {
241         int dns_size = (int(ddata[0]) << 8) | ddata[1];
242         ddata += 2;
243         dlength -= 2;
244         if (dns_size != dlength)
245             return Packet::ERROR;
246     }
247 
248     DNSMessage message(ddata, dlength, packet.m_ip_header);
249 
250     DNSMessage::Header& header    = message.m_header;
251     IP_header&          ip_header = message.m_ip_header;
252 
253     if (message.m_error != 0)
254         return Packet::ERROR;
255 
256     if (!header.qr and header.qdcount == 0)
257         return Packet::ERROR;
258 
259     Row* r = &destination_row;
260 
261     m_ip_helper.assign(r, &ip_header, columns);
262 
263     for (auto i = columns.begin(), end = columns.end(); i != end; ++i) {
264         switch (*i) {
265         case COLUMN_MSG_ID:
266             acc_msg_id.value(r) = header.id;
267             break;
268 
269         case COLUMN_MSG_SIZE:
270             acc_msg_size.value(r) = message.m_length;
271             break;
272 
273         case COLUMN_QR:
274             acc_qr.value(r) = header.qr;
275             break;
276 
277         case COLUMN_AA:
278             acc_aa.value(r) = header.aa;
279             break;
280 
281         case COLUMN_TC:
282             acc_tc.value(r) = header.tc;
283             break;
284 
285         case COLUMN_RD:
286             acc_rd.value(r) = header.rd;
287             break;
288 
289         case COLUMN_CD:
290             acc_cd.value(r) = header.cd;
291             break;
292 
293         case COLUMN_RA:
294             acc_ra.value(r) = header.ra;
295             break;
296 
297         case COLUMN_AD:
298             acc_ad.value(r) = header.ad;
299             break;
300 
301         case COLUMN_OPCODE:
302             acc_opcode.value(r) = header.opcode;
303             break;
304 
305         case COLUMN_RCODE:
306             acc_rcode.value(r) = header.rcode;
307             break;
308 
309         case COLUMN_QD_COUNT:
310             acc_qd_count.value(r) = header.qdcount;
311             break;
312 
313         case COLUMN_AN_COUNT:
314             acc_an_count.value(r) = header.ancount;
315             break;
316 
317         case COLUMN_NS_COUNT:
318             acc_ns_count.value(r) = header.nscount;
319             break;
320 
321         case COLUMN_AR_COUNT:
322             acc_ar_count.value(r) = header.arcount;
323             break;
324 
325         case COLUMN_QTYPE:
326             acc_qtype.value(r) = message.m_questions[0].qtype;
327             break;
328 
329         case COLUMN_QCLASS:
330             acc_qclass.value(r) = message.m_questions[0].qclass;
331             break;
332 
333         case COLUMN_QNAME:
334             acc_qname.value(r) = RefCountString::construct(message.m_questions[0].qname);
335             break;
336 
337         case COLUMN_EDNS0:
338             acc_edns0.value(r) = message.m_edns0 ? 1 : 0;
339             break;
340 
341         case COLUMN_DO:
342             acc_do.value(r) = message.m_edns0 ? message.m_do : 0;
343             break;
344 
345         case COLUMN_EXTENDED_RCODE:
346             acc_extended_rcode.value(r) = message.m_edns0 ? message.m_extended_rcode : 0;
347             break;
348 
349         case COLUMN_EDNS_VERSION:
350             acc_edns_version.value(r) = message.m_edns0 ? message.m_edns_version : 0;
351             break;
352 
353         case COLUMN_Z:
354             acc_z.value(r) = message.m_edns0 ? message.m_z : 0;
355             break;
356 
357         case COLUMN_UDP_SIZE:
358             acc_udp_size.value(r) = message.m_edns0 ? message.m_udp_size : 0;
359             break;
360 
361         case COLUMN_ANAME:
362             acc_aname.value(r) = header.ancount ? RefCountString::construct(message.m_answer[0].name) : RefCountString::construct("");
363             break;
364 
365         case COLUMN_ATYPE:
366             acc_atype.value(r) = header.ancount ? message.m_answer[0].type : 0;
367             break;
368 
369         case COLUMN_ACLASS:
370             acc_aclass.value(r) = header.ancount ? message.m_answer[0].rr_class : 0;
371             break;
372 
373         case COLUMN_ATTL:
374             acc_attl.value(r) = header.ancount ? message.m_answer[0].ttl : 0;
375             break;
376 
377         case COLUMN_EDNS0_ECS:
378             acc_edns0_ecs.value(r) = message.m_edns0_ecs ? 1 : 0;
379             break;
380 
381         case COLUMN_EDNS0_ECS_FAMILY:
382             acc_edns0_ecs_family.value(r) = message.m_edns0_ecs_family;
383             break;
384 
385         case COLUMN_EDNS0_ECS_SOURCE:
386             acc_edns0_ecs_source.value(r) = message.m_edns0_ecs_source;
387             break;
388 
389         case COLUMN_EDNS0_ECS_SCOPE:
390             acc_edns0_ecs_scope.value(r) = message.m_edns0_ecs_scope;
391             break;
392 
393         case COLUMN_EDNS0_ECS_ADDRESS:
394             if (message.m_edns0_ecs_addr_set && message.m_edns0_ecs_family == 1)
395                 acc_edns0_ecs_address.value(r) = v4_addr2str(message.m_edns0_ecs_addr);
396             else if (message.m_edns0_ecs_addr_set && message.m_edns0_ecs_family == 2)
397                 acc_edns0_ecs_address.value(r) = v6_addr2str(message.m_edns0_ecs_addr);
398             else
399                 acc_edns0_ecs_address.value(r) = RefCountString::construct("");
400             break;
401         }
402     }
403 
404     return Packet::OK;
405 }
406 
407 } // namespace packetq
408