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