From: Serhii Vlasiuk -X (svlasiuk - SOFTSERVE INC at Cisco) Date: Fri, 11 Aug 2023 17:36:45 +0000 (+0000) Subject: Pull request #3936: Dns response ip/name parser X-Git-Tag: 3.1.69.0~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55e50633171adc8c1c9c452520d33f70c0886cbe;p=thirdparty%2Fsnort3.git Pull request #3936: Dns response ip/name parser Merge in SNORT/snort3 from ~SVLASIUK/snort3:dns_name_parser to master Squashed commit of the following: commit 81500ab8cd6138545a0c60009eda898e88de0e62 Author: Serhii Vlasiuk Date: Tue Jul 25 18:50:36 2023 +0300 dns: parse and publish dns response with ip, fqdn/ttl data added publish_response new dns inspector option --- diff --git a/src/pub_sub/CMakeLists.txt b/src/pub_sub/CMakeLists.txt index 6ce86c532..c8af9e779 100644 --- a/src/pub_sub/CMakeLists.txt +++ b/src/pub_sub/CMakeLists.txt @@ -26,12 +26,14 @@ set (PUB_SUB_INCLUDES smb_events.h ssh_events.h ssl_events.h + dns_events.h ) add_library( pub_sub OBJECT ${PUB_SUB_INCLUDES} cip_events.cc http_events.cc + dns_events.cc http_request_body_event.cc sip_events.cc ) diff --git a/src/pub_sub/dns_events.cc b/src/pub_sub/dns_events.cc new file mode 100644 index 000000000..73c7497fe --- /dev/null +++ b/src/pub_sub/dns_events.cc @@ -0,0 +1,75 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// dns_events.cc author Serhii Vlasiuk + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dns_events.h" + +#include "service_inspectors/dns/dns.h" + +using namespace snort; + +void IPFqdnCacheItem::add_ip(const SfIp& ip) +{ + if (ip.is_set()) + ips.emplace_back(ip); +} + +void IPFqdnCacheItem::add_fqdn(const FqdnTtl& fqdn_ttl) +{ + if (fqdn_ttl.fqdn.empty()) + return; + + if (std::find_if(fqdns.cbegin(), fqdns.cend(), + [&fqdn_ttl](const FqdnTtl& i){ return i.fqdn == fqdn_ttl.fqdn; }) != fqdns.end()) + return; + + fqdns.emplace_back(fqdn_ttl); +} + +void DnsResponseDataEvents::add_ip(const DnsResponseIp& ip) +{ + dns_ips.emplace_back(ip); +} + +void DnsResponseDataEvents::add_fqdn(DnsResponseFqdn& fqdn, uint32_t ttl) +{ + fqdn.update_ttl(ttl); + dns_fqdns.emplace_back(fqdn); +} + +void DnsResponseDataEvents::get_dns_data(IPFqdnCacheItem& ip_fqdn_cache_item) +{ + for (auto& it: dns_ips) + ip_fqdn_cache_item.add_ip(it.get_ip()); + + // don't add fqdns without ips + if (ip_fqdn_cache_item.ips.empty()) + return; + + for (auto& it: dns_fqdns) + ip_fqdn_cache_item.add_fqdn(it.get_fqdn()); +} + +bool DnsResponseDataEvents::empty() const +{ + return (dns_ips.empty() or dns_fqdns.empty()); +} diff --git a/src/pub_sub/dns_events.h b/src/pub_sub/dns_events.h new file mode 100644 index 000000000..ca92e1406 --- /dev/null +++ b/src/pub_sub/dns_events.h @@ -0,0 +1,78 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// dns_events.h author Serhii Vlasiuk + +#ifndef DNS_EVENTS_H +#define DNS_EVENTS_H + +// This event allows the dns service inspector to publish dns response +// for use by data bus subscribers + +#include "framework/data_bus.h" +#include "sfip/sf_ip.h" + +struct FqdnTtl +{ + FqdnTtl(const std::string& fqdn, uint32_t ttl) : + fqdn(fqdn), ttl(ttl) + {} + + std::string fqdn; + uint32_t ttl; +}; + +struct IPFqdnCacheItem +{ + void add_ip(const snort::SfIp& ip); + void add_fqdn(const FqdnTtl& fqdn_ttl); + + std::vector ips; + std::vector fqdns; +}; + +struct DnsEventIds +{ + enum : unsigned + { + DNS_RESPONSE_DATA, + num_ids + }; +}; + +const snort::PubKey dns_pub_key { "dns", DnsEventIds::num_ids }; + +class DnsResponseIp; +class DnsResponseFqdn; + +namespace snort +{ +class SO_PUBLIC DnsResponseDataEvents : public snort::DataEvent +{ +public: + void add_ip(const DnsResponseIp& event); + void add_fqdn(DnsResponseFqdn& event, uint32_t ttl); + void get_dns_data(IPFqdnCacheItem& ip_fqdn_cache_item); + bool empty() const; + +private: + std::vector dns_ips; + std::vector dns_fqdns; +}; +} + +#endif diff --git a/src/service_inspectors/CMakeLists.txt b/src/service_inspectors/CMakeLists.txt index c4d54ac27..bfac57111 100644 --- a/src/service_inspectors/CMakeLists.txt +++ b/src/service_inspectors/CMakeLists.txt @@ -28,7 +28,6 @@ if (STATIC_INSPECTORS) $ $ $ - $ $ $ $ @@ -50,6 +49,7 @@ set(STATIC_SERVICE_INSPECTOR_PLUGINS $ $ $ + $ ${STATIC_INSPECTOR_OBJS} CACHE INTERNAL "STATIC_SERVICE_INSPECTOR_PLUGINS" ) diff --git a/src/service_inspectors/dns/CMakeLists.txt b/src/service_inspectors/dns/CMakeLists.txt index 151d3ae57..9a5ca65ed 100644 --- a/src/service_inspectors/dns/CMakeLists.txt +++ b/src/service_inspectors/dns/CMakeLists.txt @@ -2,16 +2,18 @@ set( FILE_LIST dns.cc dns.h + dns_config.cc + dns_config.h dns_module.cc dns_module.h dns_splitter.cc dns_splitter.h ) -if (STATIC_INSPECTORS) - add_library( dns OBJECT ${FILE_LIST}) +# if (STATIC_INSPECTORS) +add_library( dns OBJECT ${FILE_LIST}) -else (STATIC_INSPECTORS) - add_dynamic_module(dns inspectors ${FILE_LIST}) +# else (STATIC_INSPECTORS) +# add_dynamic_module(dns inspectors ${FILE_LIST}) -endif (STATIC_INSPECTORS) +# endif (STATIC_INSPECTORS) diff --git a/src/service_inspectors/dns/dns.cc b/src/service_inspectors/dns/dns.cc index eb5b66104..b874faa4e 100644 --- a/src/service_inspectors/dns/dns.cc +++ b/src/service_inspectors/dns/dns.cc @@ -28,6 +28,7 @@ #include "dns.h" #include "detection/detection_engine.h" +#include "dns_config.h" #include "log/messages.h" #include "profiler/profiler.h" #include "protocols/packet.h" @@ -35,6 +36,7 @@ #include "dns_module.h" #include "dns_splitter.h" +#include "pub_sub/dns_events.h" using namespace snort; @@ -58,13 +60,12 @@ const PegInfo dns_peg_names[] = /* * Function prototype(s) */ -static void snort_dns(Packet* p); +static void snort_dns(Packet* p, const DnsConfig* dns_config); unsigned DnsFlowData::inspector_id = 0; DnsFlowData::DnsFlowData() : FlowData(inspector_id) { - memset(&session, 0, sizeof(session)); dnsstats.concurrent_sessions++; if(dnsstats.max_concurrent_sessions < dnsstats.concurrent_sessions) dnsstats.max_concurrent_sessions = dnsstats.concurrent_sessions; @@ -76,6 +77,16 @@ DnsFlowData::~DnsFlowData() dnsstats.concurrent_sessions--; } +bool DNSData::publish_response() const +{ + return (dns_config->publish_response and state == DNS_RESP_STATE_ANS_RR); +} + +bool DNSData::has_events() const +{ + return !dns_events.empty(); +} + static DNSData* SetNewDNSData(Packet* p) { DnsFlowData* fd; @@ -109,7 +120,6 @@ static DNSData* get_dns_session_data(Packet* p, bool from_server, DNSData& udpSe return nullptr; } - memset(&udpSessionData, 0, sizeof(udpSessionData)); return &udpSessionData; } @@ -280,7 +290,7 @@ static uint16_t ParseDNSHeader( } static uint16_t ParseDNSName( - const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData) + const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData, bool parse_dns_name = false) { uint16_t bytes_required = dnsSessionData->curr_txt.txt_len - dnsSessionData->curr_txt.txt_bytes_seen; @@ -338,7 +348,23 @@ static uint16_t ParseDNSName( { /* If this one is a relative offset, read that extra byte */ dnsSessionData->curr_txt.offset |= *data; + if (parse_dns_name) + { + // parse recursively relative name + dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_SIZE; + return ParseDNSName(&dnsSessionData->data[0] + dnsSessionData->curr_txt.offset, + dnsSessionData->bytes_unused, dnsSessionData, parse_dns_name); + } } + + if (parse_dns_name) + { + if (!dnsSessionData->curr_txt.dns_name.empty()) + dnsSessionData->curr_txt.dns_name += "."; + + dnsSessionData->curr_txt.dns_name.append((const char*)data, bytes_required); + } + data += bytes_required; dnsSessionData->bytes_seen_curr_rec += bytes_required; dnsSessionData->curr_txt.txt_bytes_seen += bytes_required; @@ -384,7 +410,7 @@ static uint16_t ParseDNSQuestion( if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE) { dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE; - memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); + dnsSessionData->curr_txt = DNSNameState(); data = data + bytes_used; bytes_unused = new_bytes_unused; @@ -451,13 +477,16 @@ static uint16_t ParseDNSAnswer( if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_RR_NAME_COMPLETE) { + if (dnsSessionData->publish_response()) + dnsSessionData->cur_fqdn_event = DnsResponseFqdn(data, bytes_unused, dnsSessionData); + uint16_t new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData); uint16_t bytes_used = bytes_unused - new_bytes_unused; if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE) { dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE; - memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); + dnsSessionData->curr_txt = DNSNameState(); data = data + bytes_used; } bytes_unused = new_bytes_unused; @@ -717,8 +746,22 @@ static uint16_t ParseDNSRData( bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); break; case DNS_RR_TYPE_A: - case DNS_RR_TYPE_NS: + case DNS_RR_TYPE_AAAA: + if (dnsSessionData->publish_response()) + { + dnsSessionData->dns_events.add_fqdn(dnsSessionData->cur_fqdn_event, dnsSessionData->curr_rr.ttl); + dnsSessionData->dns_events.add_ip(DnsResponseIp(data, dnsSessionData->curr_rr.type)); + } + + bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); + break; case DNS_RR_TYPE_CNAME: + if (dnsSessionData->publish_response()) + dnsSessionData->dns_events.add_fqdn(dnsSessionData->cur_fqdn_event, dnsSessionData->curr_rr.ttl); + + bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); + break; + case DNS_RR_TYPE_NS: case DNS_RR_TYPE_SOA: case DNS_RR_TYPE_WKS: case DNS_RR_TYPE_PTR: @@ -736,11 +779,17 @@ static uint16_t ParseDNSRData( return bytes_unused; } -static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) +static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData, bool& needNextPacket) { uint16_t bytes_unused = p->dsize; int i; const unsigned char* data = p->data; + if (dnsSessionData->dns_config->publish_response and dnsSessionData->data.empty()) + { + dnsSessionData->data.resize(bytes_unused); + memcpy((void*)&dnsSessionData->data[0], data, bytes_unused); + dnsSessionData->bytes_unused = bytes_unused; + } while (bytes_unused) { @@ -767,7 +816,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) } else { - /* No more data */ + needNextPacket = true; return; } @@ -800,7 +849,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) } else { - /* No more data */ + needNextPacket = true; return; } } @@ -819,7 +868,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) if (bytes_unused == 0) { - /* No more data */ + needNextPacket = true; return; } @@ -835,7 +884,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) bytes_unused = ParseDNSRData(data, bytes_unused, dnsSessionData); if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE) { - /* Out of data, pick up on the next packet */ + needNextPacket = true; return; } else @@ -847,7 +896,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ - memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); + dnsSessionData->curr_txt = DNSNameState(); } data = p->data + (p->dsize - bytes_unused); } @@ -892,7 +941,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ - memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); + dnsSessionData->curr_txt = DNSNameState(); } data = p->data + (p->dsize - bytes_unused); } @@ -937,7 +986,7 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ - memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); + dnsSessionData->curr_txt = DNSNameState(); } data = p->data + (p->dsize - bytes_unused); } @@ -951,7 +1000,103 @@ static void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData) } } -static void snort_dns(Packet* p) +SfIp DnsResponseIp::get_ip() +{ + SfIp ip; + int family = 0; + switch (type) + { + case DNS_RR_TYPE_A: + family = AF_INET; + break; + case DNS_RR_TYPE_AAAA: + family = AF_INET6; + break; + } + + if (family and strlen((const char*)data)) + ip.set(data, family); + + return ip; +} + +FqdnTtl DnsResponseFqdn::get_fqdn() +{ + std::string dns_name; + ParseDNSName(data, bytes_unused, dnsSessionData.get(), true); + + if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE) + dnsSessionData->curr_txt.get_dns_name(dns_name); + + return FqdnTtl(dns_name, dnsSessionData->curr_rr.ttl); +} + +void DnsResponseFqdn::update_ttl(uint32_t ttl) +{ + dnsSessionData->curr_rr.ttl = ttl; +} + +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- + +class Dns : public Inspector +{ +public: + Dns(DnsModule*); + ~Dns() override; + + void eval(Packet*) override; + StreamSplitter* get_splitter(bool) override; + bool configure(snort::SnortConfig*) override; + void show(const snort::SnortConfig*) const override; + static unsigned get_pub_id() { return pub_id; } + +private: + const DnsConfig* config = nullptr; + static unsigned pub_id; +}; + +unsigned Dns::pub_id = 0; + +Dns::Dns(DnsModule* m) +{ + config = m->get_config(); + assert(config); +} + +Dns::~Dns() +{ + delete config; +} + +void Dns::show(const SnortConfig*) const +{ + config->show(); +} + +void Dns::eval(Packet* p) +{ + // precondition - what we registered for + assert((p->is_udp() and p->dsize and p->data) or p->has_tcp_data()); + assert(p->flow); + + ++dnsstats.packets; + snort_dns(p, config); +} + +bool Dns::configure(snort::SnortConfig*) +{ + pub_id = DataBus::get_id(dns_pub_key); + return true; +} + +StreamSplitter* Dns::get_splitter(bool c2s) +{ + return new DnsSplitter(c2s); +} + +static void snort_dns(Packet* p, const DnsConfig* dns_config) { Profile profile(dnsPerfStats); @@ -989,9 +1134,14 @@ static void snort_dns(Packet* p) if (dnsSessionData->flags & DNS_FLAG_NOT_DNS) return; + dnsSessionData->dns_config = dns_config; if ( from_server ) { - ParseDNSResponseMessage(p, dnsSessionData); + bool needNextPacket = false; + ParseDNSResponseMessage(p, dnsSessionData, needNextPacket); + + if (!needNextPacket and dnsSessionData->has_events()) + DataBus::publish(Dns::get_pub_id(), DnsEventIds::DNS_RESPONSE_DATA, dnsSessionData->dns_events); } else { @@ -999,37 +1149,6 @@ static void snort_dns(Packet* p) } } -//------------------------------------------------------------------------- -// class stuff -//------------------------------------------------------------------------- - -class Dns : public Inspector -{ -public: - Dns(DnsModule*); - - void eval(Packet*) override; - StreamSplitter* get_splitter(bool) override; -}; - -Dns::Dns(DnsModule*) -{ } - -void Dns::eval(Packet* p) -{ - // precondition - what we registered for - assert((p->is_udp() and p->dsize and p->data) or p->has_tcp_data()); - assert(p->flow); - - ++dnsstats.packets; - snort_dns(p); -} - -StreamSplitter* Dns::get_splitter(bool c2s) -{ - return new DnsSplitter(c2s); -} - //------------------------------------------------------------------------- // api stuff //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dns/dns.h b/src/service_inspectors/dns/dns.h index b981e5bb8..4dceb409f 100644 --- a/src/service_inspectors/dns/dns.h +++ b/src/service_inspectors/dns/dns.h @@ -24,6 +24,8 @@ #include "flow/flow.h" +#include "pub_sub/dns_events.h" + // Implementation header with definitions, datatypes and flowdata class for // DNS service inspector. @@ -33,12 +35,12 @@ struct DNSHdr { - uint16_t id; - uint16_t flags; - uint16_t questions; - uint16_t answers; - uint16_t authorities; - uint16_t additionals; + uint16_t id = 0; + uint16_t flags = 0; + uint16_t questions = 0; + uint16_t answers = 0; + uint16_t authorities = 0; + uint16_t additionals = 0; }; #define DNS_HDR_FLAG_REPLY_CODE_MASK 0x000F @@ -54,29 +56,36 @@ struct DNSHdr struct DNSQuestion { - uint16_t type; - uint16_t dns_class; + uint16_t type = 0; + uint16_t dns_class = 0; }; struct DNSRR { - uint16_t type; - uint16_t dns_class; - uint32_t ttl; - uint16_t length; + uint16_t type = 0; + uint16_t dns_class = 0; + uint32_t ttl = 0; + uint16_t length = 0; }; // FIXIT-L replace alerted/relative to bool? struct DNSNameState { - uint32_t txt_count; - uint32_t total_txt_len; - uint8_t txt_len; - uint8_t txt_bytes_seen; - uint8_t name_state; - uint8_t alerted; - uint16_t offset; - uint8_t relative; + uint32_t txt_count = 0; + uint32_t total_txt_len = 0; + uint8_t txt_len = 0; + uint8_t txt_bytes_seen = 0; + uint8_t name_state = 0; + uint8_t alerted = 0; + uint16_t offset = 0; + uint8_t relative = 0; + std::string dns_name; + + void get_dns_name(std::string& name) const + { + if (dns_name.size()) + name = dns_name; + } }; // FIXIT-L remove obsolete flags? @@ -96,6 +105,7 @@ struct DNSNameState #define DNS_RR_TYPE_MINFO 0x000e // experimental #define DNS_RR_TYPE_MX 0x000f #define DNS_RR_TYPE_TXT 0x0010 +#define DNS_RR_TYPE_AAAA 0x001c #define DNS_FLAG_NOT_DNS 0x01 @@ -149,21 +159,68 @@ struct DNSNameState #define DNS_RESP_STATE_AUTH_RR 0x50 #define DNS_RESP_STATE_ADD_RR 0x60 +class DnsConfig; +struct DNSData; + +class DnsResponseFqdn +{ +public: + DnsResponseFqdn() + {} + + DnsResponseFqdn(const unsigned char* data, uint16_t bytes_unused, DNSData* dnsSessionData) : + data(data), bytes_unused(bytes_unused), dnsSessionData(std::make_shared(*dnsSessionData)) + {} + + FqdnTtl get_fqdn(); + void update_ttl(uint32_t ttl); + +private: + const unsigned char* data = nullptr; + uint16_t bytes_unused = 0; + std::shared_ptr dnsSessionData; +}; + // Per-session data block containing current state // of the DNS inspector for the session. struct DNSData { - uint32_t state; // The current state of the session. - uint16_t curr_rec; // Record number for the current record - uint16_t curr_rec_length; - uint16_t bytes_seen_curr_rec; - uint16_t length; - uint8_t curr_rec_state; + uint32_t state = 0; // The current state of the session. + uint16_t curr_rec = 0; // Record number for the current record + uint16_t curr_rec_length = 0; + uint16_t bytes_seen_curr_rec = 0; + uint16_t length = 0; + uint16_t bytes_unused = 0; + uint8_t curr_rec_state = 0; DNSHdr hdr; // Copy of the data from the DNS Header DNSQuestion curr_q; DNSRR curr_rr; DNSNameState curr_txt; - uint8_t flags; + uint8_t flags = 0; + std::vector data; + const DnsConfig* dns_config = nullptr; + snort::DnsResponseDataEvents dns_events; + DnsResponseFqdn cur_fqdn_event; + + bool publish_response() const; + bool has_events() const; +}; + +class DnsResponseIp +{ +public: + DnsResponseIp() + {} + + DnsResponseIp(const unsigned char* data, uint16_t type) : + data(data), type(type) + {} + + snort::SfIp get_ip(); + +private: + const unsigned char* data = nullptr; + uint16_t type = 0; }; class DnsFlowData : public snort::FlowData diff --git a/src/service_inspectors/dns/dns_config.cc b/src/service_inspectors/dns/dns_config.cc new file mode 100644 index 000000000..567c55c96 --- /dev/null +++ b/src/service_inspectors/dns/dns_config.cc @@ -0,0 +1,34 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// dns_config.cc author Serhii Vlasiuk + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dns_config.h" + +#include "log/messages.h" + +using namespace snort; + +void DnsConfig::show() const +{ + ConfigLogger::log_value("publish_response", publish_response); +} diff --git a/src/service_inspectors/dns/dns_config.h b/src/service_inspectors/dns/dns_config.h new file mode 100644 index 000000000..0ac9d47b7 --- /dev/null +++ b/src/service_inspectors/dns/dns_config.h @@ -0,0 +1,35 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// dns_config.h author Serhii Vlasiuk + +#ifndef DNS_CONFIG_H +#define DNS_CONFIG_H + +class DnsConfig +{ +public: + DnsConfig() = default; + ~DnsConfig() = default; + + void show() const; + + bool publish_response = false; +}; + +#endif diff --git a/src/service_inspectors/dns/dns_module.cc b/src/service_inspectors/dns/dns_module.cc index a45eceec1..b4b12cc0e 100644 --- a/src/service_inspectors/dns/dns_module.cc +++ b/src/service_inspectors/dns/dns_module.cc @@ -24,6 +24,8 @@ #include "dns_module.h" +#include "dns_config.h" + using namespace snort; using namespace std; @@ -36,6 +38,8 @@ using namespace std; static const Parameter s_params[] = { + { "publish_response", Parameter::PT_BOOL, nullptr, "false", "parse and publish dns responses" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -55,6 +59,29 @@ static const RuleMap dns_rules[] = DnsModule::DnsModule() : Module(DNS_NAME, DNS_HELP, s_params) { } +DnsModule::~DnsModule() +{ + delete config; +} + +bool DnsModule::begin(const char*, int, SnortConfig*) +{ + if (!config) + config = new DnsConfig; + + return true; +} + +bool DnsModule::set(const char*, snort::Value& val, snort::SnortConfig*) +{ + if (val.is("publish_response")) + { + config->publish_response = val.get_bool(); + } + + return true; +} + const RuleMap* DnsModule::get_rules() const { return dns_rules; } @@ -67,3 +94,10 @@ PegCount* DnsModule::get_counts() const ProfileStats* DnsModule::get_profile() const { return &dnsPerfStats; } +const DnsConfig* DnsModule::get_config() +{ + DnsConfig* tmp = config; + config = nullptr; + return tmp; +} + diff --git a/src/service_inspectors/dns/dns_module.h b/src/service_inspectors/dns/dns_module.h index dd9b43b8e..c14bceb86 100644 --- a/src/service_inspectors/dns/dns_module.h +++ b/src/service_inspectors/dns/dns_module.h @@ -40,6 +40,7 @@ struct SnortConfig; #define DNS_NAME "dns" #define DNS_HELP "dns inspection" +class DnsConfig; struct DnsStats { @@ -58,9 +59,10 @@ class DnsModule : public snort::Module { public: DnsModule(); + ~DnsModule() override; - bool set(const char*, snort::Value&, snort::SnortConfig*) override - { return false; } + bool begin(const char*, int, snort::SnortConfig*) override; + bool set(const char*, snort::Value&, snort::SnortConfig*) override; unsigned get_gid() const override { return GID_DNS; } @@ -69,12 +71,16 @@ public: const PegInfo* get_pegs() const override; PegCount* get_counts() const override; snort::ProfileStats* get_profile() const override; + const DnsConfig* get_config(); Usage get_usage() const override { return INSPECT; } bool is_bindable() const override { return true; } + +private: + DnsConfig* config = nullptr; }; #endif