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 #ifndef __packetq_dns_h
23 #define __packetq_dns_h
24 
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "output.h"
31 #include "packet_handler.h"
32 #include "tcp.h"
33 
34 #define IPPROTO_ICMP 1
35 
36 namespace packetq {
37 
38 extern char visible_char_map[256];
39 
40 class DNSMessage {
41 public:
42     class Header {
43     public:
44         int  id;
45         int  z;
46         bool qr;
47         int  opcode;
48         bool aa;
49         bool tc;
50         bool rd;
51         bool ra;
52         bool ad;
53         bool cd;
54         int  rcode;
55         int  qdcount;
56         int  ancount;
57         int  nscount;
58         int  arcount;
Header()59         Header()
60             : z(0)
61         {
62             id      = 0;
63             qr      = 0;
64             opcode  = 0;
65             aa      = 0;
66             tc      = 0;
67             rd      = 0;
68             ra      = 0;
69             ad      = 0;
70             cd      = 0;
71             rcode   = 0;
72             qdcount = 0;
73             ancount = 0;
74             nscount = 0;
75             arcount = 0;
76         }
parse(DNSMessage & p)77         void parse(DNSMessage& p)
78         {
79             /*
80             From rfc 2929
81                                           1  1  1  1  1  1
82             0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
83             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
84             |                      ID                       |
85             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
86             |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
87             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
88             |                QDCOUNT/ZOCOUNT                |
89             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
90             |                ANCOUNT/PRCOUNT                |
91             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
92             |                NSCOUNT/UPCOUNT                |
93             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
94             |                    ARCOUNT                    |
95             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
96             */
97 
98             id      = p.get_ushort(0);
99             qr      = p.get_bit(2, 0);
100             opcode  = p.get_bits(2, 1, 4);
101             aa      = p.get_bit(2, 5);
102             tc      = p.get_bit(2, 6);
103             rd      = p.get_bit(2, 7);
104             ra      = p.get_bit(2, 8);
105             ad      = p.get_bit(2, 10);
106             cd      = p.get_bit(2, 11);
107             rcode   = p.get_bits(2, 12, 4);
108             qdcount = p.get_ushort(4);
109             ancount = p.get_ushort(6);
110             nscount = p.get_ushort(8);
111             arcount = p.get_ushort(10);
112         }
113     };
114     class Question {
115     public:
116         char qname[0x2000];
117         int  qtype;
118         int  qclass;
119 
Question()120         Question()
121         {
122             qname[0] = 0;
123             qtype    = 0;
124             qclass   = 0;
125         }
126 
parse(DNSMessage & m,int offs)127         int parse(DNSMessage& m, int offs)
128         {
129             offs  = m.parse_dname(qname, sizeof(qname), offs);
130             qtype = m.get_ushort(offs);
131             offs += 2;
132             qclass = m.get_ushort(offs);
133             offs += 2;
134             return offs;
135         }
136     };
137 
138     class RR {
139     public:
140         char         name[0x2000];
141         int          type;
142         int          rr_class;
143         unsigned int ttl;
144         int          rdlength;
145         int          doffs;
146 
RR()147         RR()
148         {
149             name[0]  = 0;
150             type     = 0;
151             rr_class = 0;
152             ttl      = 0;
153             rdlength = 0;
154             doffs    = 0;
155         }
156 
parse(DNSMessage & m,int offs)157         int parse(DNSMessage& m, int offs)
158         {
159             offs = m.parse_dname(name, sizeof(name), offs);
160             type = m.get_ushort(offs);
161             if (type == 41) {
162                 m.m_opt_rr     = this;
163                 m.m_new_opt_rr = true;
164             }
165             offs += 2;
166             rr_class = m.get_ushort(offs);
167             offs += 2;
168             ttl = m.get_ushort(offs) << 16;
169             ttl |= m.get_ushort(offs + 2);
170             offs += 4;
171             rdlength = m.get_ushort(offs);
172             offs += 2;
173             doffs = offs;
174             offs += rdlength;
175             return offs;
176         }
177     };
178 
179     IP_header&     m_ip_header;
180     unsigned char* m_data;
181     int            m_length;
182     Header         m_header;
183     Question       m_questions[2];
184     RR             m_answer[2];
185     RR             m_authority[2];
186     RR             m_additional[2];
187     RR*            m_opt_rr;
188     bool           m_new_opt_rr;
189     int            m_error;
190     bool           m_edns0;
191     bool           m_do;
192     int            m_extended_rcode;
193     int            m_edns_version;
194     int            m_z;
195     int            m_udp_size;
196     bool           m_edns0_ecs;
197     int            m_edns0_ecs_family;
198     int            m_edns0_ecs_source;
199     int            m_edns0_ecs_scope;
200     in6addr_t      m_edns0_ecs_addr;
201     bool           m_edns0_ecs_addr_set;
202 
DNSMessage(unsigned char * data,int len,IP_header & head)203     DNSMessage(unsigned char* data, int len, IP_header& head)
204         : m_ip_header(head)
205     {
206         m_opt_rr             = 0;
207         m_new_opt_rr         = false;
208         m_error              = 0;
209         m_data               = data;
210         m_length             = len;
211         m_edns0              = false;
212         m_do                 = false;
213         m_extended_rcode     = 0;
214         m_edns_version       = 0;
215         m_z                  = 0;
216         m_udp_size           = 0;
217         m_edns0_ecs          = false;
218         m_edns0_ecs_family   = 0;
219         m_edns0_ecs_source   = 0;
220         m_edns0_ecs_scope    = 0;
221         m_edns0_ecs_addr_set = false;
222 
223         parse();
224     }
parse_dname(char * out,int size,int offs)225     int parse_dname(char* out, int size, int offs)
226     {
227         int p         = 0;
228         int savedoffs = 0;
229         int n         = get_ubyte(offs++);
230         if (n == 0)
231             out[p++] = '.';
232 
233         while (n > 0) {
234             while (n >= 192) {
235                 if (savedoffs) {
236                     out[p++] = 0;
237                     return savedoffs;
238                 }
239                 savedoffs = offs + 1;
240                 int n2    = get_ubyte(offs++);
241                 int ptr   = (n & 63) * 0x100 + n2;
242                 offs      = ptr;
243                 n         = get_ubyte(offs++);
244             }
245 
246             // if the string is too long restart and mess it up
247             if (n + 20 + p > size / 2)
248                 p = 0;
249 
250             while (n-- > 0) {
251                 out[p++] = visible_char_map[get_ubyte(offs++)];
252             }
253             out[p++] = '.';
254             n        = get_ubyte(offs++);
255         }
256         if (savedoffs)
257             offs = savedoffs;
258         out[p++] = 0;
259         return offs;
260     }
parse_opt_rr()261     void parse_opt_rr()
262     {
263         if (m_opt_rr) {
264             if (!m_edns0) {
265                 m_edns0           = true;
266                 unsigned long ttl = m_opt_rr->ttl;
267                 m_do              = (ttl >> 15) & 1;
268                 m_extended_rcode  = ttl >> 24;
269                 m_edns_version    = (ttl >> 16) & 0xff;
270                 m_z               = ttl & 0x7fff;
271                 m_udp_size        = m_opt_rr->rr_class;
272             }
273             if (((m_opt_rr->ttl >> 16) & 0xff) == 0 && m_opt_rr->rdlength > 0) {
274                 // Parse this OPT RR that is EDNS0
275                 int rdlen  = m_opt_rr->rdlength,
276                     offs   = m_opt_rr->doffs,
277                     opcode = 0,
278                     oplen  = 0;
279 
280                 while (rdlen > 3) {
281                     // Minimum op code and length
282                     opcode = get_ushort(offs);
283                     oplen  = get_ushort(offs + 2);
284                     offs += 4;
285                     rdlen -= 4;
286 
287                     if (rdlen < oplen)
288                         break;
289 
290                     if (opcode == 8 && !m_edns0_ecs && oplen > 3) {
291                         // ECS - Client Subnet - RFC7871
292                         m_edns0_ecs        = true;
293                         m_edns0_ecs_family = get_ushort(offs);
294                         m_edns0_ecs_source = get_ubyte(offs + 2);
295                         m_edns0_ecs_scope  = get_ubyte(offs + 3);
296 
297                         int addrlen = (m_edns0_ecs_source / 8) + (m_edns0_ecs_source % 8 ? 1 : 0);
298                         int fill    = 0;
299 
300                         if (addrlen <= (oplen - 4)) {
301                             switch (m_edns0_ecs_family) {
302                             case 1:
303                                 fill                 = 4;
304                                 m_edns0_ecs_addr_set = true;
305                                 break;
306                             case 2:
307                                 fill                 = 16;
308                                 m_edns0_ecs_addr_set = true;
309                                 break;
310                             }
311 
312                             int a, b;
313                             for (a = 0, b = 15; fill && b > -1; fill--, b--) {
314                                 if (a < addrlen) {
315                                     m_edns0_ecs_addr.__in6_u.__u6_addr8[b] = get_ubyte(offs + 4 + a);
316                                     a++;
317                                 } else {
318                                     m_edns0_ecs_addr.__in6_u.__u6_addr8[b] = 0;
319                                 }
320                             }
321                         }
322                     }
323 
324                     rdlen -= oplen;
325                     offs += oplen;
326                 }
327             }
328         }
329     }
parse()330     void parse()
331     {
332         m_header.parse(*this);
333         int offs = 12;
334         int q    = 0;
335         int cnt  = m_header.qdcount;
336         while (cnt-- > 0) {
337             offs = m_questions[q].parse(*this, offs);
338             if (offs > m_length) {
339                 m_questions[q].qname[0] = 0;
340                 m_error                 = offs;
341                 return;
342             }
343             q = 1; // not ++ ignore further Q's
344         }
345         q   = 0;
346         cnt = m_header.ancount;
347         while (cnt-- > 0) {
348             offs = m_answer[q].parse(*this, offs);
349             q    = 1; // not ++ ignore further Q's
350             if (offs > m_length) {
351                 m_error = offs;
352                 return;
353             }
354         }
355         q   = 0;
356         cnt = m_header.nscount;
357         while (cnt-- > 0) {
358             offs = m_authority[q].parse(*this, offs);
359             q    = 1; // not ++ ignore further Q's
360             if (offs > m_length) {
361                 m_error = offs;
362                 return;
363             }
364         }
365         q   = 0;
366         cnt = m_header.arcount;
367         while (cnt-- > 0) {
368             offs = m_additional[q].parse(*this, offs);
369             q    = 1; // not ++ ignore further Q's
370             if (offs > m_length) {
371                 m_error = offs;
372                 return;
373             }
374             if (m_new_opt_rr) {
375                 parse_opt_rr();
376                 m_new_opt_rr = false;
377             }
378         }
379         if (offs > m_length)
380             m_error = offs;
381     }
382 
get_ubyte(int offs)383     unsigned int get_ubyte(int offs)
384     {
385         if (offs >= m_length)
386             return 0;
387         return int(m_data[offs]);
388     }
389     // returns 16 bit number at byte offset offs
get_ushort(int offs)390     unsigned int get_ushort(int offs)
391     {
392         if ((offs + 1) >= m_length)
393             return 0;
394         return (int(m_data[offs]) << 8) | int(m_data[offs + 1]);
395     }
get_uint32(int offs)396     uint32_t get_uint32(int offs)
397     {
398         if ((offs + 3) >= m_length)
399             return 0;
400         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]);
401     }
get_bit(int offs,int bit)402     bool get_bit(int offs, int bit)
403     {
404         if (offs >= m_length)
405             return 0;
406         return ((get_ushort(offs) << bit) & 0x8000) == 0x8000;
407     }
get_bits(int offs,int bit,int bits)408     unsigned int get_bits(int offs, int bit, int bits)
409     {
410         if (offs >= m_length)
411             return 0;
412         return ((get_ushort(offs) << bit) & 0xffff) >> (16 - bits);
413     }
414 };
415 
416 class Parse_dns : public Packet_handler {
417 public:
418     enum {
419         COLUMN_QNAME = IP_header_to_table::COLUMN_FRAGMENTS + 1,
420         COLUMN_ANAME,
421         COLUMN_MSG_ID,
422         COLUMN_MSG_SIZE,
423         COLUMN_OPCODE,
424         COLUMN_RCODE,
425         COLUMN_EXTENDED_RCODE,
426         COLUMN_EDNS_VERSION,
427         COLUMN_Z,
428         COLUMN_UDP_SIZE,
429         COLUMN_QD_COUNT,
430         COLUMN_AN_COUNT,
431         COLUMN_NS_COUNT,
432         COLUMN_AR_COUNT,
433         COLUMN_QTYPE,
434         COLUMN_QCLASS,
435         COLUMN_ATYPE,
436         COLUMN_ACLASS,
437         COLUMN_ATTL,
438         COLUMN_AA,
439         COLUMN_TC,
440         COLUMN_RD,
441         COLUMN_CD,
442         COLUMN_RA,
443         COLUMN_AD,
444         COLUMN_DO,
445         COLUMN_EDNS0,
446         COLUMN_QR,
447         COLUMN_EDNS0_ECS,
448         COLUMN_EDNS0_ECS_FAMILY,
449         COLUMN_EDNS0_ECS_SOURCE,
450         COLUMN_EDNS0_ECS_SCOPE,
451         COLUMN_EDNS0_ECS_ADDRESS,
452     };
453 
454     Parse_dns();
455 
456     virtual void on_table_created(Table* table, const std::vector<int>& columns);
457     virtual Packet::ParseResult parse(Packet& packet, const std::vector<int>& columns, Row& destination_row, bool sample);
458 
459     void add_packet_columns();
460     void add_lookup_tables();
461 
462 private:
463     Str_conv converter;
464 
465     IP_header_to_table m_ip_helper;
466 
467     Int_accessor  acc_s;
468     Int_accessor  acc_us;
469     Int_accessor  acc_ether_type;
470     Int_accessor  acc_protocol;
471     Int_accessor  acc_src_port;
472     Int_accessor  acc_msg_id;
473     Int_accessor  acc_msg_size;
474     Int_accessor  acc_opcode;
475     Int_accessor  acc_rcode;
476     Int_accessor  acc_extended_rcode;
477     Int_accessor  acc_edns_version;
478     Int_accessor  acc_z;
479     Int_accessor  acc_udp_size;
480     Int_accessor  acc_qd_count;
481     Int_accessor  acc_an_count;
482     Int_accessor  acc_ns_count;
483     Int_accessor  acc_ar_count;
484     Int_accessor  acc_qtype;
485     Int_accessor  acc_qclass;
486     Int_accessor  acc_atype;
487     Int_accessor  acc_aclass;
488     Int_accessor  acc_attl;
489     Int_accessor  acc_edns0_ecs_family;
490     Int_accessor  acc_edns0_ecs_source;
491     Int_accessor  acc_edns0_ecs_scope;
492     Bool_accessor acc_qr;
493     Bool_accessor acc_aa;
494     Bool_accessor acc_tc;
495     Bool_accessor acc_rd;
496     Bool_accessor acc_cd;
497     Bool_accessor acc_ra;
498     Bool_accessor acc_ad;
499     Bool_accessor acc_do;
500     Bool_accessor acc_edns0;
501     Bool_accessor acc_edns0_ecs;
502     Text_accessor acc_qname;
503     Text_accessor acc_aname;
504     Text_accessor acc_src_addr;
505     Text_accessor acc_dst_addr;
506     Text_accessor acc_edns0_ecs_address;
507 };
508 
509 } // namespace packetq
510 
511 #endif // __packetq_dns_h
512