00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2004-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019
00020 // dns.cc author Steven Sturges
00021 // Alert for DNS client rdata buffer overflow.
00022 // Alert for Obsolete or Experimental RData types (per RFC 1035)
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027
00028 #include "dns.h"
00029
00030 #include "detection/detection_engine.h"
00031 #include "log/messages.h"
00032 #include "profiler/profiler.h"
00033 #include "protocols/packet.h"
00034 #include "stream/stream.h"
00035
00036 #include "main/snort_debug.h"
00037
00038
00039 #include "dns_module.h"
00040
00041 #define MAX_UDP_PAYLOAD 0x1FFF
00042 #define DNS_RR_PTR 0xC0
00043
00044 THREAD_LOCAL ProfileStats dnsPerfStats;
00045 THREAD_LOCAL DnsStats dnsstats;
00046
00047 const PegInfo dns_peg_names[] =
00048 {
00049 { CountType::SUM, "packets", "total packets processed" },
00050 { CountType::SUM, "requests", "total dns requests" },
00051 { CountType::SUM, "responses", "total dns responses" },
00052 { CountType::NOW, "concurrent_sessions", "total concurrent dns sessions" },
00053 { CountType::MAX, "max_concurrent_sessions", "maximum concurrent dns sessions" },
00054
00055 { CountType::END, nullptr, nullptr }
00056 };
00057
00058 /*
00059 * Function prototype(s)
00060 */
00061 static void snort_dns(Packet* p);
00062
00063 unsigned DnsFlowData::inspector_id = 0;
00064
00065 DNSData udpSessionData;
00066
00067 DnsFlowData::DnsFlowData() : FlowData(inspector_id)
00068 {
00069 memset(&session, 0, sizeof(session));
00070 dnsstats.concurrent_sessions++;
00071 if(dnsstats.max_concurrent_sessions < dnsstats.concurrent_sessions)
00072 dnsstats.max_concurrent_sessions = dnsstats.concurrent_sessions;
00073 }
00074
00075 DnsFlowData::~DnsFlowData()
00076 {
00077 assert(dnsstats.concurrent_sessions > 0);
00078 dnsstats.concurrent_sessions--;
00079 }
00080
00081 static DNSData* SetNewDNSData(Packet* p)
00082 {
00083 DnsFlowData* fd;
00084
00085 if (p->is_udp())
00086 return nullptr;
00087
00088 fd = new DnsFlowData;
00089
00090 p->flow->set_flow_data(fd);
00091 return &fd->session;
00092 }
00093
00094 static DNSData* get_dns_session_data(Packet* p, bool from_server)
00095 {
00096 DnsFlowData* fd;
00097
00098 if (p->is_udp())
00099 {
00100 if(p->dsize > MAX_UDP_PAYLOAD)
00101 return nullptr;
00102
00103 if(!from_server)
00104 {
00105 if (p->dsize < (sizeof(DNSHdr) + sizeof(DNSQuestion) + 2))
00106 return nullptr;
00107 }
00108 else
00109 {
00110 if (p->dsize < (sizeof(DNSHdr)))
00111 return nullptr;
00112 }
00113
00114 memset(&udpSessionData, 0, sizeof(udpSessionData));
00115 return &udpSessionData;
00116 }
00117
00118 fd = (DnsFlowData*)((p->flow)->get_flow_data(DnsFlowData::inspector_id));
00119 return fd ? &fd->session : nullptr;
00120 }
00121
00122 static uint16_t ParseDNSHeader(
00123 const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData)
00124 {
00125 if ( !bytes_unused )
00126 return 0;
00127
00128 switch (dnsSessionData->state)
00129 {
00130 case DNS_RESP_STATE_LENGTH:
00131 /* First two bytes are length in TCP */
00132 dnsSessionData->length = ((uint8_t)*data) << 8;
00133 dnsSessionData->state = DNS_RESP_STATE_LENGTH_PART;
00134 data++;
00135
00136 if ( !--bytes_unused )
00137 return 0;
00138 // Fall through
00139
00140 case DNS_RESP_STATE_LENGTH_PART:
00141 dnsSessionData->length |= ((uint8_t)*data);
00142 dnsSessionData->state = DNS_RESP_STATE_HDR_ID;
00143 data++;
00144
00145 if ( !--bytes_unused )
00146 return 0;
00147 // Fall through
00148
00149 case DNS_RESP_STATE_HDR_ID:
00150 dnsSessionData->hdr.id = (uint8_t)*data << 8;
00151 dnsSessionData->state = DNS_RESP_STATE_HDR_ID_PART;
00152 data++;
00153
00154 if ( !--bytes_unused )
00155 return 0;
00156 // Fall through
00157
00158 case DNS_RESP_STATE_HDR_ID_PART:
00159 dnsSessionData->hdr.id |= (uint8_t)*data;
00160 dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS;
00161 data++;
00162
00163 if ( !--bytes_unused )
00164 return 0;
00165 // Fall through
00166
00167 case DNS_RESP_STATE_HDR_FLAGS:
00168 dnsSessionData->hdr.flags = (uint8_t)*data << 8;
00169 dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS_PART;
00170 data++;
00171
00172 if ( !--bytes_unused )
00173 return 0;
00174 // Fall through
00175
00176 case DNS_RESP_STATE_HDR_FLAGS_PART:
00177 dnsSessionData->hdr.flags |= (uint8_t)*data;
00178 dnsSessionData->state = DNS_RESP_STATE_HDR_QS;
00179 data++;
00180
00181 if ( !--bytes_unused )
00182 return 0;
00183 // Fall through
00184
00185 case DNS_RESP_STATE_HDR_QS:
00186 dnsSessionData->hdr.questions = (uint8_t)*data << 8;
00187 dnsSessionData->state = DNS_RESP_STATE_HDR_QS_PART;
00188 data++;
00189
00190 if ( !--bytes_unused )
00191 return 0;
00192 // Fall through
00193
00194 case DNS_RESP_STATE_HDR_QS_PART:
00195 dnsSessionData->hdr.questions |= (uint8_t)*data;
00196 dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS;
00197 data++;
00198
00199 if ( !--bytes_unused )
00200 return 0;
00201 // Fall through
00202
00203 case DNS_RESP_STATE_HDR_ANSS:
00204 dnsSessionData->hdr.answers = (uint8_t)*data << 8;
00205 dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS_PART;
00206 data++;
00207
00208 if ( !--bytes_unused )
00209 return 0;
00210 // Fall through
00211
00212 case DNS_RESP_STATE_HDR_ANSS_PART:
00213 dnsSessionData->hdr.answers |= (uint8_t)*data;
00214 dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS;
00215 data++;
00216
00217 if ( !--bytes_unused )
00218 return 0;
00219 // Fall through
00220
00221 case DNS_RESP_STATE_HDR_AUTHS:
00222 dnsSessionData->hdr.authorities = (uint8_t)*data << 8;
00223 dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS_PART;
00224 data++;
00225
00226 if ( !--bytes_unused )
00227 return 0;
00228 // Fall through
00229
00230 case DNS_RESP_STATE_HDR_AUTHS_PART:
00231 dnsSessionData->hdr.authorities |= (uint8_t)*data;
00232 dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS;
00233 data++;
00234
00235 if ( !--bytes_unused )
00236 return 0;
00237 // Fall through
00238
00239 case DNS_RESP_STATE_HDR_ADDS:
00240 dnsSessionData->hdr.additionals = (uint8_t)*data << 8;
00241 dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS_PART;
00242 data++;
00243
00244 if ( !--bytes_unused )
00245 return 0;
00246 // Fall through
00247
00248 case DNS_RESP_STATE_HDR_ADDS_PART:
00249 dnsSessionData->hdr.additionals |= (uint8_t)*data;
00250 dnsSessionData->state = DNS_RESP_STATE_QUESTION;
00251 bytes_unused--;
00252 break;
00253 }
00254
00255 return bytes_unused;
00256 }
00257
00258 static uint16_t ParseDNSName(
00259 const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData)
00260 {
00261 uint16_t bytes_required = dnsSessionData->curr_txt.txt_len -
00262 dnsSessionData->curr_txt.txt_bytes_seen;
00263
00264 while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_NAME_COMPLETE)
00265 {
00266 if (bytes_unused == 0)
00267 {
00268 return bytes_unused;
00269 }
00270
00271 switch (dnsSessionData->curr_txt.name_state)
00272 {
00273 case DNS_RESP_STATE_NAME_SIZE:
00274 dnsSessionData->curr_txt.txt_len = (uint8_t)*data;
00275 data++;
00276 bytes_unused--;
00277 dnsSessionData->bytes_seen_curr_rec++;
00278 if (dnsSessionData->curr_txt.txt_len == 0)
00279 {
00280 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE;
00281 return bytes_unused;
00282 }
00283
00284 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME;
00285 dnsSessionData->curr_txt.txt_bytes_seen = 0;
00286
00287 if ((dnsSessionData->curr_txt.txt_len & DNS_RR_PTR) == DNS_RR_PTR)
00288 {
00289 /* A reference to another location...
00290 This is an offset */
00291 dnsSessionData->curr_txt.offset = (dnsSessionData->curr_txt.txt_len & ~0xC0) << 8;
00292 bytes_required = dnsSessionData->curr_txt.txt_len = 1;
00293 dnsSessionData->curr_txt.relative = 1;
00294 /* Setup to read 2nd Byte of Location */
00295 }
00296 else
00297 {
00298 bytes_required = dnsSessionData->curr_txt.txt_len;
00299 dnsSessionData->curr_txt.offset = 0;
00300 dnsSessionData->curr_txt.relative = 0;
00301 }
00302
00303 if (bytes_unused == 0)
00304 {
00305 return bytes_unused;
00306 }
00307
00308 /* Fall through */
00309 case DNS_RESP_STATE_NAME:
00310 if (bytes_required <= bytes_unused)
00311 {
00312 bytes_unused -= bytes_required;
00313 if (dnsSessionData->curr_txt.relative)
00314 {
00315 /* If this one is a relative offset, read that extra byte */
00316 dnsSessionData->curr_txt.offset |= *data;
00317 }
00318 data += bytes_required;
00319 dnsSessionData->bytes_seen_curr_rec += bytes_required;
00320 dnsSessionData->curr_txt.txt_bytes_seen += bytes_required;
00321
00322 if (bytes_unused == 0)
00323 {
00324 return bytes_unused;
00325 }
00326 }
00327 else
00328 {
00329 dnsSessionData->bytes_seen_curr_rec+= bytes_unused;
00330 dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused;
00331 return 0;
00332 }
00333 if (dnsSessionData->curr_txt.relative)
00334 {
00335 /* And since its relative, we're done */
00336 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE;
00337 return bytes_unused;
00338 }
00339 break;
00340 }
00341
00342 /* Go to the next portion of the name */
00343 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_SIZE;
00344 }
00345
00346 return bytes_unused;
00347 }
00348
00349 static uint16_t ParseDNSQuestion(
00350 const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData)
00351 {
00352 uint16_t bytes_used = 0;
00353 uint16_t new_bytes_unused = 0;
00354
00355 if ( !bytes_unused )
00356 return 0;
00357
00358 if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_Q_NAME_COMPLETE)
00359 {
00360 new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData);
00361 bytes_used = bytes_unused - new_bytes_unused;
00362
00363 if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE)
00364 {
00365 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE;
00366 memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
00367 data = data + bytes_used;
00368 bytes_unused = new_bytes_unused;
00369
00370 if ( !bytes_unused )
00371 return 0; /* ran out of data */
00372 }
00373 else
00374 {
00375 /* Should be 0 -- ran out of data */
00376 return new_bytes_unused;
00377 }
00378 }
00379
00380 switch (dnsSessionData->curr_rec_state)
00381 {
00382 case DNS_RESP_STATE_Q_TYPE:
00383 dnsSessionData->curr_q.type = (uint8_t)*data << 8;
00384 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE_PART;
00385 data++;
00386
00387 if ( !--bytes_unused )
00388 return 0;
00389 // Fall through
00390
00391 case DNS_RESP_STATE_Q_TYPE_PART:
00392 dnsSessionData->curr_q.type |= (uint8_t)*data;
00393 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS;
00394 data++;
00395
00396 if ( !--bytes_unused )
00397 return 0;
00398 // Fall through
00399
00400 case DNS_RESP_STATE_Q_CLASS:
00401 dnsSessionData->curr_q.dns_class = (uint8_t)*data << 8;
00402 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS_PART;
00403 data++;
00404
00405 if ( !--bytes_unused )
00406 return 0;
00407 // Fall through
00408
00409 case DNS_RESP_STATE_Q_CLASS_PART:
00410 dnsSessionData->curr_q.dns_class |= (uint8_t)*data;
00411 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_COMPLETE;
00412 bytes_unused--;
00413 break;
00414 }
00415
00416 return bytes_unused;
00417 }
00418
00419 static uint16_t ParseDNSAnswer(
00420 const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData)
00421 {
00422 uint16_t bytes_used = 0;
00423 uint16_t new_bytes_unused = 0;
00424
00425 if ( !bytes_unused )
00426 return 0;
00427
00428 if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_RR_NAME_COMPLETE)
00429 {
00430 new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData);
00431 bytes_used = bytes_unused - new_bytes_unused;
00432
00433 if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE)
00434 {
00435 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE;
00436 memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
00437 data = data + bytes_used;
00438 }
00439 bytes_unused = new_bytes_unused;
00440
00441 if ( !bytes_unused )
00442 return 0; /* ran out of data */
00443 }
00444
00445 switch (dnsSessionData->curr_rec_state)
00446 {
00447 case DNS_RESP_STATE_RR_TYPE:
00448 dnsSessionData->curr_rr.type = (uint8_t)*data << 8;
00449 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE_PART;
00450 data++;
00451
00452 if ( !--bytes_unused )
00453 return 0;
00454 // Fall through
00455
00456 case DNS_RESP_STATE_RR_TYPE_PART:
00457 dnsSessionData->curr_rr.type |= (uint8_t)*data;
00458 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS;
00459 data++;
00460
00461 if ( !--bytes_unused )
00462 return 0;
00463 // Fall through
00464
00465 case DNS_RESP_STATE_RR_CLASS:
00466 dnsSessionData->curr_rr.dns_class = (uint8_t)*data << 8;
00467 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS_PART;
00468 data++;
00469
00470 if ( !--bytes_unused )
00471 return 0;
00472 // Fall through
00473
00474 case DNS_RESP_STATE_RR_CLASS_PART:
00475 dnsSessionData->curr_rr.dns_class |= (uint8_t)*data;
00476 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL;
00477 data++;
00478
00479 if ( !--bytes_unused )
00480 return 0;
00481 // Fall through
00482
00483 case DNS_RESP_STATE_RR_TTL:
00484 dnsSessionData->curr_rr.ttl = (uint8_t)*data << 24;
00485 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL_PART;
00486 dnsSessionData->bytes_seen_curr_rec = 1;
00487 data++;
00488
00489 if ( !--bytes_unused )
00490 return 0;
00491 // Fall through
00492
00493 case DNS_RESP_STATE_RR_TTL_PART:
00494 while (dnsSessionData->bytes_seen_curr_rec < 4)
00495 {
00496 dnsSessionData->bytes_seen_curr_rec++;
00497 dnsSessionData->curr_rr.ttl |=
00498 (uint8_t)*data << (4-dnsSessionData->bytes_seen_curr_rec)*8;
00499 data++;
00500
00501 if ( !--bytes_unused )
00502 return 0;
00503 }
00504 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH;
00505 // Fall through
00506
00507 case DNS_RESP_STATE_RR_RDLENGTH:
00508 dnsSessionData->curr_rr.length = (uint8_t)*data << 8;
00509 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH_PART;
00510 data++;
00511
00512 if ( !--bytes_unused )
00513 return 0;
00514 // Fall through
00515
00516 case DNS_RESP_STATE_RR_RDLENGTH_PART:
00517 dnsSessionData->curr_rr.length |= (uint8_t)*data;
00518 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_START;
00519 bytes_unused--;
00520 break;
00521 }
00522
00523 return bytes_unused;
00524 }
00525
00526 /* The following check is to look for an attempt to exploit
00527 * a vulnerability in the DNS client, per MS 06-041.
00528 *
00529 * For details, see:
00530 * http://www.microsoft.com/technet/security/bulletin/ms06-007.mspx
00531 * http://cve.mitre.org/cgi-bin/cvename.cgi?name=2006-3441
00532 *
00533 * Vulnerability Research by Lurene Grenier, Judy Novak,
00534 * and Brian Caswell.
00535 */
00536 static uint16_t CheckRRTypeTXTVuln(
00537 const unsigned char* data,
00538 uint16_t bytes_unused,
00539 DNSData* dnsSessionData)
00540 {
00541 uint16_t bytes_required = dnsSessionData->curr_txt.txt_len -
00542 dnsSessionData->curr_txt.txt_bytes_seen;
00543
00544 while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_RR_NAME_COMPLETE)
00545 {
00546 if (dnsSessionData->bytes_seen_curr_rec == dnsSessionData->curr_rr.length)
00547 {
00548 /* Done with the name */
00549 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_COMPLETE;
00550 /* Got to the end of the rdata in this packet! */
00551 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE;
00552 return bytes_unused;
00553 }
00554
00555 if (bytes_unused == 0)
00556 {
00557 return bytes_unused;
00558 }
00559
00560 switch (dnsSessionData->curr_txt.name_state)
00561 {
00562 case DNS_RESP_STATE_RR_NAME_SIZE:
00563 dnsSessionData->curr_txt.txt_len = (uint8_t)*data;
00564 dnsSessionData->curr_txt.txt_count++;
00565
00566 /* include the NULL */
00567 dnsSessionData->curr_txt.total_txt_len += dnsSessionData->curr_txt.txt_len + 1;
00568
00569 if (!dnsSessionData->curr_txt.alerted)
00570 {
00571 uint32_t overflow_check = (dnsSessionData->curr_txt.txt_count * 4) +
00572 (dnsSessionData->curr_txt.total_txt_len * 2) + 4;
00573 /* if txt_count * 4 + total_txt_len * 2 + 4 > FFFF, vulnerability! */
00574 if (overflow_check > 0xFFFF)
00575 {
00576 /* Alert on obsolete DNS RR types */
00577 DetectionEngine::queue_event(GID_DNS, DNS_EVENT_RDATA_OVERFLOW);
00578
00579 dnsSessionData->curr_txt.alerted = 1;
00580 }
00581 }
00582
00583 data++;
00584 bytes_unused--;
00585 dnsSessionData->bytes_seen_curr_rec++;
00586 if (dnsSessionData->curr_txt.txt_len > 0)
00587 {
00588 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME;
00589 dnsSessionData->curr_txt.txt_bytes_seen = 0;
00590 bytes_required = dnsSessionData->curr_txt.txt_len;
00591 }
00592 else
00593 {
00594 continue;
00595 }
00596 if (bytes_unused == 0)
00597 {
00598 return bytes_unused;
00599 }
00600 /* Fall through */
00601 case DNS_RESP_STATE_RR_NAME:
00602 if (bytes_required <= bytes_unused)
00603 {
00604 bytes_unused -= bytes_required;
00605 dnsSessionData->bytes_seen_curr_rec += bytes_required;
00606 data += bytes_required;
00607 dnsSessionData->curr_txt.txt_bytes_seen += bytes_required;
00608 if (bytes_unused == 0)
00609 {
00610 return bytes_unused;
00611 }
00612 }
00613 else
00614 {
00615 dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused;
00616 dnsSessionData->bytes_seen_curr_rec += bytes_unused;
00617 return 0;
00618 }
00619 break;
00620 }
00621
00622 /* Go to the next portion of the name */
00623 dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_SIZE;
00624 }
00625
00626 return bytes_unused;
00627 }
00628
00629 static uint16_t SkipDNSRData(
00630 const unsigned char*,
00631 uint16_t bytes_unused,
00632 DNSData* dnsSessionData)
00633 {
00634 uint16_t bytes_required = dnsSessionData->curr_rr.length - dnsSessionData->bytes_seen_curr_rec;
00635
00636 if (bytes_required <= bytes_unused)
00637 {
00638 bytes_unused -= bytes_required;
00639 dnsSessionData->bytes_seen_curr_rec += bytes_required;
00640 }
00641 else
00642 {
00643 dnsSessionData->bytes_seen_curr_rec += bytes_unused;
00644 return 0;
00645 }
00646
00647 /* Got to the end of the rdata in this packet! */
00648 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE;
00649 return bytes_unused;
00650 }
00651
00652 static uint16_t ParseDNSRData(
00653 const unsigned char* data,
00654 uint16_t bytes_unused,
00655 DNSData* dnsSessionData)
00656 {
00657 if (bytes_unused == 0)
00658 {
00659 return bytes_unused;
00660 }
00661
00662 switch (dnsSessionData->curr_rr.type)
00663 {
00664 case DNS_RR_TYPE_TXT:
00665 /* Check for RData Overflow */
00666 bytes_unused = CheckRRTypeTXTVuln(data, bytes_unused, dnsSessionData);
00667 break;
00668
00669 case DNS_RR_TYPE_MD:
00670 case DNS_RR_TYPE_MF:
00671 /* Alert on obsolete DNS RR types */
00672 DetectionEngine::queue_event(GID_DNS, DNS_EVENT_OBSOLETE_TYPES);
00673 bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
00674 break;
00675
00676 case DNS_RR_TYPE_MB:
00677 case DNS_RR_TYPE_MG:
00678 case DNS_RR_TYPE_MR:
00679 case DNS_RR_TYPE_NULL:
00680 case DNS_RR_TYPE_MINFO:
00681 /* Alert on experimental DNS RR types */
00682 DetectionEngine::queue_event(GID_DNS, DNS_EVENT_EXPERIMENTAL_TYPES);
00683 bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
00684 break;
00685 case DNS_RR_TYPE_A:
00686 case DNS_RR_TYPE_NS:
00687 case DNS_RR_TYPE_CNAME:
00688 case DNS_RR_TYPE_SOA:
00689 case DNS_RR_TYPE_WKS:
00690 case DNS_RR_TYPE_PTR:
00691 case DNS_RR_TYPE_HINFO:
00692 case DNS_RR_TYPE_MX:
00693 bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
00694 break;
00695 default:
00696 /* Not one of the known types. Stop looking at this session
00697 * as DNS. */
00698 dnsSessionData->flags |= DNS_FLAG_NOT_DNS;
00699 break;
00700 }
00701
00702 return bytes_unused;
00703 }
00704
00705 static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData)
00706 {
00707 uint16_t bytes_unused = p->dsize;
00708 int i;
00709 const unsigned char* data = p->data;
00710
00711 while (bytes_unused)
00712 {
00713 /* Parse through the DNS Header */
00714 if (dnsSessionData->state < DNS_RESP_STATE_QUESTION)
00715 {
00716 /* Length only applies on a TCP packet, skip to header ID
00717 * if at beginning of a UDP Response.
00718 */
00719 if ((dnsSessionData->state == DNS_RESP_STATE_LENGTH) &&
00720 p->is_udp())
00721 {
00722 dnsSessionData->state = DNS_RESP_STATE_HDR_ID;
00723 }
00724
00725 bytes_unused = ParseDNSHeader(data, bytes_unused, dnsSessionData);
00726
00727 if (dnsSessionData->hdr.flags & DNS_HDR_FLAG_RESPONSE)
00728 dnsstats.responses++;
00729
00730 if (bytes_unused > 0)
00731 {
00732 data = p->data + (p->dsize - bytes_unused);
00733 }
00734 else
00735 {
00736 /* No more data */
00737 return;
00738 }
00739
00740 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME;
00741 dnsSessionData->curr_rec = 0;
00742 }
00743
00744 /* Print out the header (but only once -- when we're ready to parse the Questions */
00745 if ((dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_NAME) &&
00746 (dnsSessionData->curr_rec == 0))
00747 {
00748 DebugFormat(DEBUG_DNS,
00749 "DNS Header: length %d, id 0x%x, flags 0x%x, "
00750 "questions %d, answers %d, authorities %d, additionals %d\n",
00751 dnsSessionData->length, dnsSessionData->hdr.id,
00752 dnsSessionData->hdr.flags, dnsSessionData->hdr.questions,
00753 dnsSessionData->hdr.answers,
00754 dnsSessionData->hdr.authorities,
00755 dnsSessionData->hdr.additionals);
00756 }
00757
00758 if (!(dnsSessionData->hdr.flags & DNS_HDR_FLAG_RESPONSE))
00759 {
00760 /* Not a response */
00761 return;
00762 }
00763
00764 /* Handle the DNS Queries */
00765 if (dnsSessionData->state == DNS_RESP_STATE_QUESTION)
00766 {
00767 /* Skip over the 4 byte question records... */
00768 for (i=dnsSessionData->curr_rec; i< dnsSessionData->hdr.questions; i++)
00769 {
00770 bytes_unused = ParseDNSQuestion(data, bytes_unused, dnsSessionData);
00771
00772 if (dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_COMPLETE)
00773 {
00774 DebugFormat(DEBUG_DNS,
00775 "DNS Question %d: type %d, class %d\n",
00776 i, dnsSessionData->curr_q.type,
00777 dnsSessionData->curr_q.dns_class);
00778
00779 dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME;
00780 dnsSessionData->curr_rec++;
00781 }
00782 if (bytes_unused > 0)
00783 {
00784 data = p->data + (p->dsize - bytes_unused);
00785 }
00786 else
00787 {
00788 /* No more data */
00789 return;
00790 }
00791 }
00792 dnsSessionData->state = DNS_RESP_STATE_ANS_RR;
00793 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00794 dnsSessionData->curr_rec = 0;
00795 }
00796
00797 /* Handle the RRs */
00798 switch (dnsSessionData->state)
00799 {
00800 case DNS_RESP_STATE_ANS_RR: /* ANSWERS section */
00801 for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.answers; i++)
00802 {
00803 bytes_unused = ParseDNSAnswer(data, bytes_unused, dnsSessionData);
00804
00805 if (bytes_unused == 0)
00806 {
00807 /* No more data */
00808 return;
00809 }
00810
00811 switch (dnsSessionData->curr_rec_state)
00812 {
00813 case DNS_RESP_STATE_RR_RDATA_START:
00814 DebugFormat(DEBUG_DNS,
00815 "DNS ANSWER RR %d: type %hu, class %hu, "
00816 "ttl %u rdlength %hu\n", i,
00817 dnsSessionData->curr_rr.type,
00818 dnsSessionData->curr_rr.dns_class,
00819 dnsSessionData->curr_rr.ttl,
00820 dnsSessionData->curr_rr.length);
00821
00822 dnsSessionData->bytes_seen_curr_rec = 0;
00823 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
00824 /* Fall through */
00825 case DNS_RESP_STATE_RR_RDATA_MID:
00826 /* Data now points to the beginning of the RDATA */
00827 data = p->data + (p->dsize - bytes_unused);
00828 bytes_unused = ParseDNSRData(data, bytes_unused, dnsSessionData);
00829 if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
00830 {
00831 /* Out of data, pick up on the next packet */
00832 return;
00833 }
00834 else
00835 {
00836 /* Go to the next record */
00837 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00838 dnsSessionData->curr_rec++;
00839
00840 if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
00841 {
00842 /* Reset the state tracking for this record */
00843 memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
00844 }
00845 data = p->data + (p->dsize - bytes_unused);
00846 }
00847 }
00848 }
00849 dnsSessionData->state = DNS_RESP_STATE_AUTH_RR;
00850 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00851 dnsSessionData->curr_rec = 0;
00852 /* Fall through */
00853 case DNS_RESP_STATE_AUTH_RR: /* AUTHORITIES section */
00854 for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.authorities; i++)
00855 {
00856 bytes_unused = ParseDNSAnswer(data, bytes_unused, dnsSessionData);
00857
00858 if (bytes_unused == 0)
00859 {
00860 /* No more data */
00861 return;
00862 }
00863
00864 switch (dnsSessionData->curr_rec_state)
00865 {
00866 case DNS_RESP_STATE_RR_RDATA_START:
00867 DebugFormat(DEBUG_DNS,
00868 "DNS AUTH RR %d: type %hu, class %hu, "
00869 "ttl %u rdlength %hu\n", i,
00870 dnsSessionData->curr_rr.type,
00871 dnsSessionData->curr_rr.dns_class,
00872 dnsSessionData->curr_rr.ttl,
00873 dnsSessionData->curr_rr.length);
00874
00875 dnsSessionData->bytes_seen_curr_rec = 0;
00876 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
00877 /* Fall through */
00878 case DNS_RESP_STATE_RR_RDATA_MID:
00879 /* Data now points to the beginning of the RDATA */
00880 data = p->data + (p->dsize - bytes_unused);
00881 bytes_unused = ParseDNSRData(data, bytes_unused, dnsSessionData);
00882 if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
00883 {
00884 /* Out of data, pick up on the next packet */
00885 return;
00886 }
00887 else
00888 {
00889 /* Go to the next record */
00890 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00891 dnsSessionData->curr_rec++;
00892
00893 if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
00894 {
00895 /* Reset the state tracking for this record */
00896 memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
00897 }
00898 data = p->data + (p->dsize - bytes_unused);
00899 }
00900 }
00901 }
00902 dnsSessionData->state = DNS_RESP_STATE_ADD_RR;
00903 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00904 dnsSessionData->curr_rec = 0;
00905 /* Fall through */
00906 case DNS_RESP_STATE_ADD_RR: /* ADDITIONALS section */
00907 for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.authorities; i++)
00908 {
00909 bytes_unused = ParseDNSAnswer(data, bytes_unused, dnsSessionData);
00910
00911 if (bytes_unused == 0)
00912 {
00913 /* No more data */
00914 return;
00915 }
00916
00917 switch (dnsSessionData->curr_rec_state)
00918 {
00919 case DNS_RESP_STATE_RR_RDATA_START:
00920 DebugFormat(DEBUG_DNS,
00921 "DNS ADDITIONAL RR %d: type %hu, class %hu, "
00922 "ttl %u rdlength %hu\n", i,
00923 dnsSessionData->curr_rr.type,
00924 dnsSessionData->curr_rr.dns_class,
00925 dnsSessionData->curr_rr.ttl,
00926 dnsSessionData->curr_rr.length);
00927
00928 dnsSessionData->bytes_seen_curr_rec = 0;
00929 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
00930 /* Fall through */
00931 case DNS_RESP_STATE_RR_RDATA_MID:
00932 /* Data now points to the beginning of the RDATA */
00933 data = p->data + (p->dsize - bytes_unused);
00934 bytes_unused = ParseDNSRData(data, bytes_unused, dnsSessionData);
00935 if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
00936 {
00937 /* Out of data, pick up on the next packet */
00938 return;
00939 }
00940 else
00941 {
00942 /* Go to the next record */
00943 dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
00944 dnsSessionData->curr_rec++;
00945
00946 if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
00947 {
00948 /* Reset the state tracking for this record */
00949 memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
00950 }
00951 data = p->data + (p->dsize - bytes_unused);
00952 }
00953 }
00954 }
00955 /* Done with this one, onto the next -- may also be in this packet */
00956 dnsSessionData->state = DNS_RESP_STATE_LENGTH;
00957 dnsSessionData->curr_rec_state = 0;
00958 dnsSessionData->curr_rec = 0;
00959 }
00960 }
00961 }
00962
00963 static void snort_dns(Packet* p)
00964 {
00965 Profile profile(dnsPerfStats);
00966
00967 // For TCP, do a few extra checks...
00968 if ( p->has_tcp_data() )
00969 {
00970 // If session picked up mid-stream, do not process further.
00971 // Would be almost impossible to tell where we are in the
00972 // data stream.
00973 if ( p->flow->get_session_flags() & SSNFLAG_MIDSTREAM )
00974 {
00975 return;
00976 }
00977
00978 if ( !Stream::is_stream_sequenced(p->flow, SSN_DIR_FROM_CLIENT) )
00979 {
00980 return;
00981 }
00982
00983 // If we're waiting on stream reassembly, don't process this packet.
00984 if ( p->packet_flags & PKT_STREAM_INSERT )
00985 {
00986 return;
00987 }
00988 }
00989
00990 // Get the direction of the packet.
00991 bool from_server = ( (p->is_from_server() ) ? true : false );
00992
00993
00994 // Attempt to get a previously allocated DNS block.
00995 DNSData* dnsSessionData = get_dns_session_data(p, from_server);
00996
00997 if (dnsSessionData == nullptr)
00998 {
00999 // Check the stream session. If it does not currently
01000 // have our DNS data-block attached, create one.
01001 dnsSessionData = SetNewDNSData(p);
01002
01003 if ( !dnsSessionData )
01004 // Could not get/create the session data for this packet.
01005 return;
01006 }
01007
01008 if (dnsSessionData->flags & DNS_FLAG_NOT_DNS)
01009 return;
01010
01011 if ( from_server )
01012 {
01013 ParseDNSResponseMessage(p, dnsSessionData);
01014 }
01015 else
01016 {
01017 dnsstats.requests++;
01018 }
01019 }
01020
01021 //-------------------------------------------------------------------------
01022 // class stuff
01023 //-------------------------------------------------------------------------
01024
01025 class Dns : public Inspector
01026 {
01027 public:
01028 Dns(DnsModule*);
01029
01030 void show(SnortConfig*) override;
01031 void eval(Packet*) override;
01032 };
01033
01034 Dns::Dns(DnsModule*)
01035 { }
01036
01037 void Dns::show(SnortConfig*)
01038 {
01039 LogMessage("DNS\n");
01040 }
01041
01042 void Dns::eval(Packet* p)
01043 {
01044 // precondition - what we registered for
01045 assert((p->is_udp() and p->dsize and p->data) or p->has_tcp_data());
01046 assert(p->flow);
01047
01048 new_invoked_inspector(16, p, 0);
01049
01050 ++dnsstats.packets;
01051 snort_dns(p);
01052 }
01053
01054 //-------------------------------------------------------------------------
01055 // api stuff
01056 //-------------------------------------------------------------------------
01057
01058 static Module* mod_ctor()
01059 { return new DnsModule; }
01060
01061 static void mod_dtor(Module* m)
01062 { delete m; }
01063
01064 static void dns_init()
01065 {
01066 DnsFlowData::init();
01067 }
01068
01069 static Inspector* dns_ctor(Module* m)
01070 {
01071 DnsModule* mod = (DnsModule*)m;
01072 return new Dns(mod);
01073 }
01074
01075 static void dns_dtor(Inspector* p)
01076 {
01077 delete p;
01078 }
01079
01080 const InspectApi dns_api =
01081 {
01082 {
01083 PT_INSPECTOR,
01084 sizeof(InspectApi),
01085 INSAPI_VERSION,
01086 0,
01087 API_RESERVED,
01088 API_OPTIONS,
01089 DNS_NAME,
01090 DNS_HELP,
01091 mod_ctor,
01092 mod_dtor
01093 },
01094 IT_SERVICE,
01095 (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
01096 nullptr, // buffers
01097 "dns",
01098 dns_init,
01099 nullptr, // pterm
01100 nullptr, // tinit
01101 nullptr, // tterm
01102 dns_ctor,
01103 dns_dtor,
01104 nullptr, // ssn
01105 nullptr // reset
01106 };
01107
01108 #ifdef BUILDING_SO
01109 SO_PUBLIC const BaseApi* snort_plugins[] =
01110 {
01111 &dns_api.base,
01112 nullptr
01113 };
01114 #else
01115 const BaseApi* sin_dns = &dns_api.base;
01116 #endif
01117
END OF CODE