From: Shravan Rangarajuvenkata (shrarang) Date: Mon, 16 Nov 2020 23:20:46 +0000 (+0000) Subject: Merge pull request #2605 in SNORT/snort3 from ~SATHIRKA/snort3:rna_dhcp_fp_framework... X-Git-Tag: 3.0.3-6~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc72773a8efe1e76bdb660dcb8edb3d764d9a954;p=thirdparty%2Fsnort3.git Merge pull request #2605 in SNORT/snort3 from ~SATHIRKA/snort3:rna_dhcp_fp_framework to master Squashed commit of the following: commit 1b3cbac56c1965b568232d886c6bb5913c18e5c9 Author: Sreeja Athirkandathil Narayanan Date: Mon Sep 21 17:29:55 2020 -0400 rna: Support DHCP fingerprint matching and event generation --- diff --git a/src/host_tracker/host_tracker.cc b/src/host_tracker/host_tracker.cc index 8a3322ee2..478b2e016 100644 --- a/src/host_tracker/host_tracker.cc +++ b/src/host_tracker/host_tracker.cc @@ -769,6 +769,13 @@ bool HostTracker::add_tcp_fingerprint(uint32_t fpid) return result.second; } +bool HostTracker::add_udp_fingerprint(uint32_t fpid) +{ + lock_guard lck(host_tracker_lock); + auto result = udp_fpids.emplace(fpid); + return result.second; +} + bool HostTracker::set_visibility(bool v) { std::lock_guard lck(host_tracker_lock); @@ -1183,4 +1190,12 @@ void HostTracker::stringify(string& str) str += string(")") + (--total ? ", " : ""); } } + + total = udp_fpids.size(); + if ( total ) + { + str += "\nudp fingerprint: "; + for ( const auto& fpid : udp_fpids ) + str += to_string(fpid) + (--total ? ", " : ""); + } } diff --git a/src/host_tracker/host_tracker.h b/src/host_tracker/host_tracker.h index e8c593297..ea8f87934 100644 --- a/src/host_tracker/host_tracker.h +++ b/src/host_tracker/host_tracker.h @@ -335,6 +335,7 @@ public: bool add_tcp_fingerprint(uint32_t fpid); bool add_ua_fingerprint(uint32_t fpid, uint32_t fp_type, bool jail_broken, const char* device_info, uint8_t max_devices); + bool add_udp_fingerprint(uint32_t fpid); // This should be updated whenever HostTracker data members are changed void stringify(std::string& str); @@ -425,6 +426,7 @@ private: std::vector services; std::vector clients; std::set, HostCacheAllocIp> tcp_fpids; + std::set, HostCacheAllocIp> udp_fpids; std::vector ua_fps; bool vlan_tag_present = false; diff --git a/src/network_inspectors/appid/appid_session.h b/src/network_inspectors/appid/appid_session.h index 31ad3525d..c0407c64c 100644 --- a/src/network_inspectors/appid/appid_session.h +++ b/src/network_inspectors/appid/appid_session.h @@ -65,9 +65,7 @@ const uint8_t* service_strstr(const uint8_t* haystack, unsigned haystack_len, #define MAX_SFTP_PACKET_COUNT 55 #define APPID_SESSION_DATA_NONE 0 -#define APPID_SESSION_DATA_DHCP_FP_DATA 2 #define APPID_SESSION_DATA_SMB_DATA 4 -#define APPID_SESSION_DATA_DHCP_INFO 5 #define APPID_SESSION_DATA_SERVICE_MODSTATE_BIT 0x20000000 #define APPID_SESSION_DATA_CLIENT_MODSTATE_BIT 0x40000000 #define APPID_SESSION_DATA_DETECTOR_MODSTATE_BIT 0x80000000 diff --git a/src/network_inspectors/appid/service_plugins/service_bootp.cc b/src/network_inspectors/appid/service_plugins/service_bootp.cc index 156a04033..5051dcd6e 100644 --- a/src/network_inspectors/appid/service_plugins/service_bootp.cc +++ b/src/network_inspectors/appid/service_plugins/service_bootp.cc @@ -25,12 +25,14 @@ #include "service_bootp.h" +#include "detection/detection_engine.h" +#include "protocols/eth.h" +#include "protocols/packet.h" +#include "pub_sub/dhcp_events.h" #include "app_info_table.h" #include "appid_config.h" #include "appid_inspector.h" #include "appid_utils/ip_funcs.h" -#include "protocols/eth.h" -#include "protocols/packet.h" using namespace snort; @@ -160,8 +162,7 @@ int BootpServiceDetector::validate(AppIdDiscoveryArgs& args) if (option53 && op55_len && (memcmp(eh->ether_src, bh->chaddr, 6) == 0)) { - if (add_dhcp_info(args.asd, op55_len, op55, op60_len, op60, bh->chaddr)) - return APPID_ENOMEM; + add_dhcp_info(args.asd, op55_len, op55, op60_len, op60, bh->chaddr); } goto inprocess; } @@ -306,39 +307,19 @@ not_compatible: return APPID_NOT_COMPATIBLE; } -void BootpServiceDetector::AppIdFreeDhcpData(DHCPData* dd) -{ - snort_free(dd); -} - -void BootpServiceDetector::AppIdFreeDhcpInfo(DHCPInfo* dd) -{ - snort_free(dd); -} - -int BootpServiceDetector::add_dhcp_info(AppIdSession& asd, unsigned op55_len, const uint8_t* op55, +void BootpServiceDetector::add_dhcp_info(AppIdSession& asd, unsigned op55_len, const uint8_t* op55, unsigned op60_len, const uint8_t* op60, const uint8_t* mac) { if (op55_len && op55_len <= DHCP_OPTION55_LEN_MAX && !asd.get_session_flags(APPID_SESSION_HAS_DHCP_FP)) { - DHCPData* rdd = (DHCPData*)snort_calloc(sizeof(*rdd)); - if (asd.add_flow_data(rdd, APPID_SESSION_DATA_DHCP_FP_DATA, - (AppIdFreeFCN)BootpServiceDetector::AppIdFreeDhcpData)) - { - BootpServiceDetector::AppIdFreeDhcpData(rdd); - return -1; - } - asd.set_session_flags(APPID_SESSION_HAS_DHCP_FP); - rdd->op55_len = (op55_len > DHCP_OP55_MAX_SIZE) ? DHCP_OP55_MAX_SIZE : op55_len; - memcpy(rdd->op55, op55, rdd->op55_len); - rdd->op60_len = (op60_len > DHCP_OP60_MAX_SIZE) ? DHCP_OP60_MAX_SIZE : op60_len; - if (op60_len) - memcpy(rdd->op60, op60, rdd->op60_len); - memcpy(rdd->eth_addr, mac, sizeof(rdd->eth_addr)); + unsigned op55_length = (op55_len > DHCP_OP55_MAX_SIZE) ? DHCP_OP55_MAX_SIZE : op55_len; + unsigned op60_length = (op60_len > DHCP_OP60_MAX_SIZE) ? DHCP_OP60_MAX_SIZE : op60_len; + Packet* p = DetectionEngine::get_current_packet(); + DHCPDataEvent event(p, op55_length, op60_length, op55, op60, mac); + DataBus::publish(DHCP_DATA_EVENT, event, p->flow); } - return 0; } static unsigned isIPv4HostMonitored(uint32_t, int32_t) @@ -351,8 +332,6 @@ void BootpServiceDetector::add_new_dhcp_lease(AppIdSession& asd, const uint8_t* int32_t zone, uint32_t subnetmask, uint32_t leaseSecs, uint32_t router) { - DHCPInfo* info; - if (memcmp(mac, zeromac, 6) == 0 || ip == 0) return; @@ -364,19 +343,9 @@ void BootpServiceDetector::add_new_dhcp_lease(AppIdSession& asd, const uint8_t* if (!(flags & IPFUNCS_HOSTS_IP)) return; - info = (DHCPInfo*)snort_calloc(sizeof(DHCPInfo)); - - if (asd.add_flow_data(info, APPID_SESSION_DATA_DHCP_INFO, - (AppIdFreeFCN)BootpServiceDetector::AppIdFreeDhcpInfo)) - { - BootpServiceDetector::AppIdFreeDhcpInfo(info); - return; - } asd.set_session_flags(APPID_SESSION_HAS_DHCP_INFO); - info->ipAddr = ip; - memcpy(info->eth_addr, mac, sizeof(info->eth_addr)); - info->subnetmask = subnetmask; - info->leaseSecs = leaseSecs; - info->router = router; + Packet* p = DetectionEngine::get_current_packet(); + DHCPInfoEvent event(p, ip, mac, subnetmask, leaseSecs, router); + DataBus::publish(DHCP_INFO_EVENT, event, p->flow); } diff --git a/src/network_inspectors/appid/service_plugins/service_bootp.h b/src/network_inspectors/appid/service_plugins/service_bootp.h index 2e098af76..32aa6a211 100644 --- a/src/network_inspectors/appid/service_plugins/service_bootp.h +++ b/src/network_inspectors/appid/service_plugins/service_bootp.h @@ -24,32 +24,9 @@ #include "service_detector.h" -#define DHCP_OP55_MAX_SIZE 64 -#define DHCP_OP60_MAX_SIZE 64 - class AppIdSession; class ServiceDiscovery; -struct DHCPData -{ - DHCPData* next; - unsigned op55_len; - unsigned op60_len; - uint8_t op55[DHCP_OP55_MAX_SIZE]; - uint8_t op60[DHCP_OP60_MAX_SIZE]; - uint8_t eth_addr[6]; -}; - -struct DHCPInfo -{ - DHCPInfo* next; - uint32_t ipAddr; - uint8_t eth_addr[6]; - uint32_t subnetmask; - uint32_t leaseSecs; - uint32_t router; -}; - class BootpServiceDetector : public ServiceDetector { public: @@ -57,12 +34,8 @@ public: int validate(AppIdDiscoveryArgs&) override; - // FIXIT-L - move to service discovery class - static void AppIdFreeDhcpData(DHCPData*); - static void AppIdFreeDhcpInfo(DHCPInfo*); - private: - int add_dhcp_info(AppIdSession&, unsigned op55_len, const uint8_t* op55, unsigned + void add_dhcp_info(AppIdSession&, unsigned op55_len, const uint8_t* op55, unsigned op60_len, const uint8_t* op60, const uint8_t* mac); void add_new_dhcp_lease(AppIdSession&, const uint8_t* mac, uint32_t ip, int32_t zone, uint32_t subnetmask, uint32_t leaseSecs, uint32_t router); diff --git a/src/network_inspectors/rna/CMakeLists.txt b/src/network_inspectors/rna/CMakeLists.txt index 800fec670..7cd8fc478 100644 --- a/src/network_inspectors/rna/CMakeLists.txt +++ b/src/network_inspectors/rna/CMakeLists.txt @@ -2,6 +2,7 @@ set (RNA_INCLUDES rna_fingerprint.h rna_fingerprint_tcp.h rna_fingerprint_ua.h + rna_fingerprint_udp.h rna_inspector.h rna_logger.h rna_name.h @@ -17,6 +18,7 @@ set ( RNA_SOURCES rna_fingerprint.h rna_fingerprint_tcp.cc rna_fingerprint_ua.cc + rna_fingerprint_udp.cc rna_inspector.cc rna_inspector.h rna_logger.cc diff --git a/src/network_inspectors/rna/dev_notes.txt b/src/network_inspectors/rna/dev_notes.txt index 2f59c2cbe..de7c2cbe2 100644 --- a/src/network_inspectors/rna/dev_notes.txt +++ b/src/network_inspectors/rna/dev_notes.txt @@ -82,8 +82,6 @@ not return prior to that to avoid leaking any host trackers. Fingerprints Fingerprints are a sequence of features in network traffic used to identify a host's operating system. -Currently only tcp fingerprints are supported, but future work may include udp fingerprints and -user agent fingerprints. Tcp fingerprints are specified in lua and read by snort at configure time. Only the SYN and SYN-ACK packets are used for fingerprint matching. We refer to the SYN packet @@ -234,3 +232,20 @@ looks like this: user_agent = { { substring = "CPU" }, { substring = "OS 3_0" }, { substring = "My Company" } }, device = "My Mobile", } + +UDP fingerprints are of two types, namely DHCP and SMB. Currently only DHCP fingerprints are +supported. Similar to TCP and user-agent based fingerprints, fingerprint patterns can be specified +in the lua configuration. DHCP fingerprint matching is based on option fields present in DHCP +Request packet and the updated lease information is obtained from the DHCP ACK packet. Appid +module processes the DHCP request packet, parses the option 55 and option 60 fields and publishes +the DHCPDataEvent. This triggers RNA fingerprint matching and event generation. While processing +DHCP ACK packet, appid extracts the leased IP, netmask and lease time and publishes the DHCPInfoEvent. +RNA generates the CHANGE_FULL_DHCP_INFO event with updated lease information. +A sample DHCP fingerprint is shown below: +{ + fpid = 111, + uuid = "12345678-1234-1234-1234-123456789111", + type = 4, + dhcp55 = "1 121 3 6 15 119 252", + dhcp60 = "dhcp 5.1.4", +} diff --git a/src/network_inspectors/rna/rna_config.h b/src/network_inspectors/rna/rna_config.h index 781802c13..8c99ba0b9 100644 --- a/src/network_inspectors/rna/rna_config.h +++ b/src/network_inspectors/rna/rna_config.h @@ -25,6 +25,7 @@ namespace snort { class TcpFpProcessor; class UaFpProcessor; +class UdpFpProcessor; } struct RnaModuleConfig @@ -34,6 +35,7 @@ struct RnaModuleConfig bool log_when_idle; snort::TcpFpProcessor* tcp_processor = nullptr; snort::UaFpProcessor* ua_processor = nullptr; + snort::UdpFpProcessor* udp_processor = nullptr; }; // Give default values so that RNA can work even if rna_conf_path is not provided diff --git a/src/network_inspectors/rna/rna_event_handler.cc b/src/network_inspectors/rna/rna_event_handler.cc index 72f8c93cb..3eb818406 100644 --- a/src/network_inspectors/rna/rna_event_handler.cc +++ b/src/network_inspectors/rna/rna_event_handler.cc @@ -23,6 +23,7 @@ #endif #include "rna_event_handler.h" +#include "pub_sub/dhcp_events.h" using namespace snort; @@ -103,3 +104,17 @@ void RnaIdleEventHandler::handle(DataEvent& event, Flow*) ++rna_stats.change_host_update; pnd.generate_change_host_update(); } + +void RnaDHCPInfoEventHandler::handle(DataEvent& event, Flow*) +{ + Profile profile(rna_perf_stats); + ++rna_stats.dhcp_info; + pnd.add_dhcp_info(event); +} + +void RnaDHCPDataEventHandler::handle(DataEvent& event, Flow*) +{ + Profile profile(rna_perf_stats); + ++rna_stats.dhcp_data; + pnd.analyze_dhcp_fingerprint(event); +} diff --git a/src/network_inspectors/rna/rna_event_handler.h b/src/network_inspectors/rna/rna_event_handler.h index 980842bc2..8bfb59600 100644 --- a/src/network_inspectors/rna/rna_event_handler.h +++ b/src/network_inspectors/rna/rna_event_handler.h @@ -126,4 +126,22 @@ private: RnaPnd& pnd; }; +class RnaDHCPInfoEventHandler : public snort::DataHandler +{ +public: + RnaDHCPInfoEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { } + void handle(snort::DataEvent&, snort::Flow*) override; +private: + RnaPnd& pnd; +}; + +class RnaDHCPDataEventHandler : public snort::DataHandler +{ +public: + RnaDHCPDataEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { } + void handle(snort::DataEvent&, snort::Flow*) override; +private: + RnaPnd& pnd; +}; + #endif diff --git a/src/network_inspectors/rna/rna_fingerprint.h b/src/network_inspectors/rna/rna_fingerprint.h index 3bb35452f..73041d426 100644 --- a/src/network_inspectors/rna/rna_fingerprint.h +++ b/src/network_inspectors/rna/rna_fingerprint.h @@ -144,6 +144,9 @@ public: std::string host_name; std::string device; + std::string dhcp55; + std::string dhcp60; + void clear() { fpid = 0; @@ -160,6 +163,8 @@ public: user_agent.clear(); host_name.clear(); device.clear(); + dhcp55.clear(); + dhcp60.clear(); } }; diff --git a/src/network_inspectors/rna/rna_fingerprint_udp.cc b/src/network_inspectors/rna/rna_fingerprint_udp.cc new file mode 100644 index 000000000..b27b4d94f --- /dev/null +++ b/src/network_inspectors/rna/rna_fingerprint_udp.cc @@ -0,0 +1,151 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- + +// rna_fingerprint_udp.cc author Sreeja Athirkandathil Narayanan + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rna_fingerprint_udp.h" + +#include + +#ifdef UNIT_TEST +#include "catch/snort_catch.h" +#endif + +#include "main/thread.h" +#include "pub_sub/dhcp_events.h" + +using namespace snort; +using namespace std; + +static THREAD_LOCAL UdpFpProcessor* udp_fp_processor = nullptr; + +void set_udp_fp_processor(UdpFpProcessor* processor) +{ + udp_fp_processor = processor; +} + +UdpFpProcessor* get_udp_fp_processor() +{ + return udp_fp_processor; +} + +static void parse_fp_element(const string& data, vector& fpe) +{ + istringstream in(data); + string tok; + while ( in >> tok ) + fpe.emplace_back(tok); +} + +DHCPFingerprint::DHCPFingerprint(const RawFingerprint& rfp) +{ + fpid = rfp.fpid; + fpuuid = rfp.fpuuid; + fp_type = rfp.fp_type; + if (!rfp.dhcp55.empty()) + parse_fp_element(rfp.dhcp55, dhcp55); + if (!rfp.dhcp60.empty()) + dhcp60 = rfp.dhcp60; +} + +void UdpFpProcessor::push(const RawFingerprint& rfp) +{ + if (rfp.fp_type == FpFingerprint::FpType::FP_TYPE_DHCP) + { + DHCPFingerprint dhcp_fp(rfp); + if (dhcp_fp.dhcp55.size() > DHCP_OP55_MAX_SIZE) + return; + push_dhcp_fp(dhcp_fp); + } +} + +static bool match_dhcp_options(const vector& options, const uint8_t* key_options) +{ + for (const auto& op : options) + { + if (op.d.value != *key_options++) + return false; + } + return true; +} + +const DHCPFingerprint* UdpFpProcessor::match_dhcp_fingerprint(const FpDHCPKey& key) const +{ + if (key.dhcp55_len == 0 || key.dhcp55_len > DHCP_OP55_MAX_SIZE) + return nullptr; + uint32_t fptype = FpFingerprint::FpType::FP_TYPE_DHCP; + for (const auto& fp: dhcp_fps) + { + if (fptype == fp.fp_type && fp.dhcp55.size() == key.dhcp55_len and + match_dhcp_options(fp.dhcp55, key.dhcp55)) + { + if (key.dhcp60 and !fp.dhcp60.empty()) + { + if(fp.dhcp60.size() == key.dhcp60_len and + !fp.dhcp60.compare((const char*) (key.dhcp60))) + return &fp; + } + else if (fp.dhcp60.empty()) + return &fp; + } + } + return nullptr; +} + +#ifdef UNIT_TEST + +TEST_CASE("match_dhcp_fingerprint", "[rna_fingerprint_udp]") +{ + set_udp_fp_processor(new UdpFpProcessor); + UdpFpProcessor* processor = get_udp_fp_processor(); + + RawFingerprint rawfp; + rawfp.fpid = 111; + rawfp.fp_type = 4; + rawfp.fpuuid = "12345678-1234-1234-1234-123456789111"; + rawfp.dhcp55 = "1 3 15 28 225"; + rawfp.dhcp60 = "dhcp 5.1.2"; + processor->push(rawfp); + + FpDHCPKey key; + key.dhcp55_len = 0; + key.dhcp60 = (const uint8_t*) "dhcp 5.1.2"; + key.dhcp60_len = 10; + // no dhcp55, only dhcp60 option, returns null + CHECK(processor->match_dhcp_fingerprint(key) == nullptr); + + rawfp.fpid = 222; + rawfp.fp_type = 4; + rawfp.fpuuid = "12345678-1234-1234-1234-123456789222"; + rawfp.dhcp55 = "1 2 45 121"; + rawfp.dhcp60 = "dhcp 5.1.3"; + processor->push(rawfp); + + uint8_t op55[] = {1, 2, 45, 121}; + key.dhcp55 = op55; + key.dhcp55_len = 4; + key.dhcp60 = (const uint8_t*) "dhcp 5.0"; + key.dhcp60_len = 8; + //dhcp60 doesn't match, returns null + CHECK(processor->match_dhcp_fingerprint(key) == nullptr); +} +#endif diff --git a/src/network_inspectors/rna/rna_fingerprint_udp.h b/src/network_inspectors/rna/rna_fingerprint_udp.h new file mode 100644 index 000000000..6d4a3f2eb --- /dev/null +++ b/src/network_inspectors/rna/rna_fingerprint_udp.h @@ -0,0 +1,73 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- + +// rna_fingerprint_udp.h author Sreeja Athirkandathil Narayanan + +#ifndef RNA_FINGERPRINT_UDP_H +#define RNA_FINGERPRINT_UDP_H + +#include +#include + +#include "rna_fingerprint.h" + +namespace snort +{ +class SO_PUBLIC DHCPFingerprint : public FpFingerprint +{ +public: + DHCPFingerprint() = default; + DHCPFingerprint(const RawFingerprint& rfp); + std::vector dhcp55; + std::string dhcp60; + + void clear() override + { + FpFingerprint::clear(); + dhcp55.clear(); + dhcp60.clear(); + } +}; + +struct FpDHCPKey +{ + unsigned dhcp55_len; + unsigned dhcp60_len; + const uint8_t* dhcp55; + const uint8_t* dhcp60; +}; + +class SO_PUBLIC UdpFpProcessor +{ +public: + void push(const RawFingerprint& rfp); + const DHCPFingerprint* match_dhcp_fingerprint(const FpDHCPKey&) const; + + void push_dhcp_fp(DHCPFingerprint& dhcp_fp) + { + dhcp_fps.emplace_back(dhcp_fp); + } +private: + std::vector dhcp_fps; +}; + +} + +snort::UdpFpProcessor* get_udp_fp_processor(); +SO_PUBLIC void set_udp_fp_processor(snort::UdpFpProcessor*); +#endif diff --git a/src/network_inspectors/rna/rna_inspector.cc b/src/network_inspectors/rna/rna_inspector.cc index 3f4221fc3..4fbab04ce 100644 --- a/src/network_inspectors/rna/rna_inspector.cc +++ b/src/network_inspectors/rna/rna_inspector.cc @@ -33,10 +33,12 @@ #include "main/snort.h" #include "managers/inspector_manager.h" #include "protocols/packet.h" +#include "pub_sub/dhcp_events.h" #include "rna_event_handler.h" #include "rna_fingerprint_tcp.h" #include "rna_fingerprint_ua.h" +#include "rna_fingerprint_udp.h" #include "rna_module.h" #include "rna_pnd.h" @@ -72,6 +74,7 @@ RnaInspector::~RnaInspector() { delete mod_conf->tcp_processor; delete mod_conf->ua_processor; + delete mod_conf->udp_processor; delete mod_conf; } } @@ -79,6 +82,8 @@ RnaInspector::~RnaInspector() bool RnaInspector::configure(SnortConfig* sc) { DataBus::subscribe_global( APPID_EVENT_ANY_CHANGE, new RnaAppidEventHandler(*pnd), sc ); + DataBus::subscribe_global( DHCP_INFO_EVENT, new RnaDHCPInfoEventHandler(*pnd), sc); + DataBus::subscribe_global( DHCP_DATA_EVENT, new RnaDHCPDataEventHandler(*pnd), sc); DataBus::subscribe_global( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpNewFlowEventHandler(*pnd), sc ); DataBus::subscribe_global( STREAM_ICMP_BIDIRECTIONAL_EVENT, new RnaIcmpBidirectionalEventHandler(*pnd), sc ); @@ -139,6 +144,7 @@ void RnaInspector::tinit() // thread local initialization set_tcp_fp_processor(mod_conf->tcp_processor); set_ua_fp_processor(mod_conf->ua_processor); + set_udp_fp_processor(mod_conf->udp_processor); } void RnaInspector::tterm() @@ -199,7 +205,8 @@ void RnaInspector::load_rna_conf() in_stream.close(); } -void RnaInspector::get_or_create_fp_processor(TcpFpProcessor*& tfp, UaFpProcessor*& uafp) +void RnaInspector::get_or_create_fp_processor(TcpFpProcessor*& tfp, UaFpProcessor*& uafp, + UdpFpProcessor*& udpfp) { if ( !mod_conf ) return; @@ -208,12 +215,15 @@ void RnaInspector::get_or_create_fp_processor(TcpFpProcessor*& tfp, UaFpProcesso mod_conf->tcp_processor = new TcpFpProcessor; if ( !mod_conf->ua_processor ) mod_conf->ua_processor = new UaFpProcessor; + if ( !mod_conf->udp_processor ) + mod_conf->udp_processor = new UdpFpProcessor; tfp = mod_conf->tcp_processor; uafp = mod_conf->ua_processor; + udpfp = mod_conf->udp_processor; } -void RnaInspector::set_fp_processor(TcpFpProcessor* tfp, UaFpProcessor* uafp) +void RnaInspector::set_fp_processor(TcpFpProcessor* tfp, UaFpProcessor* uafp, UdpFpProcessor* udpfp) { if ( !mod_conf ) return; @@ -223,6 +233,9 @@ void RnaInspector::set_fp_processor(TcpFpProcessor* tfp, UaFpProcessor* uafp) delete mod_conf->ua_processor; mod_conf->ua_processor = uafp; + + delete mod_conf->udp_processor; + mod_conf->udp_processor = udpfp; } //------------------------------------------------------------------------- @@ -307,10 +320,12 @@ TEST_CASE("RNA inspector", "[rna_inspector]") RnaInspector ins(&mod); TcpFpProcessor* tfp = nullptr; UaFpProcessor* uafp = nullptr; - ins.set_fp_processor(tfp, uafp); - ins.get_or_create_fp_processor(tfp, uafp); + UdpFpProcessor* udpfp = nullptr; + ins.set_fp_processor(tfp, uafp, udpfp); + ins.get_or_create_fp_processor(tfp, uafp, udpfp); CHECK(tfp != nullptr); CHECK(uafp != nullptr); + CHECK(udpfp != nullptr); } } #endif diff --git a/src/network_inspectors/rna/rna_inspector.h b/src/network_inspectors/rna/rna_inspector.h index 77a4ecff4..227e34419 100644 --- a/src/network_inspectors/rna/rna_inspector.h +++ b/src/network_inspectors/rna/rna_inspector.h @@ -30,6 +30,7 @@ namespace snort struct Packet; class TcpFpProcessor; class UaFpProcessor; +class UdpFpProcessor; } struct RnaConfig; @@ -49,8 +50,9 @@ public: void tinit() override; void tterm() override; - void get_or_create_fp_processor(snort::TcpFpProcessor*&, snort::UaFpProcessor*&); - void set_fp_processor(snort::TcpFpProcessor*, snort::UaFpProcessor*); + void get_or_create_fp_processor(snort::TcpFpProcessor*&, snort::UaFpProcessor*&, + snort::UdpFpProcessor*&); + void set_fp_processor(snort::TcpFpProcessor*, snort::UaFpProcessor*, snort::UdpFpProcessor*); private: void load_rna_conf(); diff --git a/src/network_inspectors/rna/rna_logger.cc b/src/network_inspectors/rna/rna_logger.cc index e8ce65b4b..0aa52d041 100644 --- a/src/network_inspectors/rna/rna_logger.cc +++ b/src/network_inspectors/rna/rna_logger.cc @@ -60,8 +60,21 @@ static inline void rna_logger_message(const RnaLoggerEvent& rle, const Packet* p SfIpString ipbuf; ip.set(rle.ip); // using this instead of packet's ip to support ARP if ( rle.mac ) - debug_logf(rna_trace, p, "RNA log: type %u, subtype %u, mac %s, ip %s\n", - rle.type, rle.subtype, macbuf, ip.ntop(ipbuf)); + { + if (rle.type == RNA_EVENT_CHANGE and rle.subtype == CHANGE_FULL_DHCP_INFO) + { + SfIp router; + SfIpString routerbuf; + router.set(rle.router); + debug_logf(rna_trace, p, "RNA DHCP full information log: type %u, " + "subtype %u, mac %s, ip %s, lease time %u, netmask %x, router %s\n", + rle.type, rle.subtype, macbuf, ip.ntop(ipbuf), rle.lease, + rle.netmask, router.ntop(routerbuf)); + } + else + debug_logf(rna_trace, p, "RNA log: type %u, subtype %u, mac %s, ip %s\n", + rle.type, rle.subtype, macbuf, ip.ntop(ipbuf)); + } else debug_logf(rna_trace, p, "RNA log: type %u, subtype %u, ip %s\n", rle.type, rle.subtype, ip.ntop(ipbuf)); @@ -170,11 +183,20 @@ void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const uint nullptr, nullptr, nullptr, cond_var); } +void RnaLogger::log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht, + const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t lease, uint32_t netmask, + const struct in6_addr* router) +{ + log(type, subtype, src_ip, src_mac, ht, p, 0, 0, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, APP_ID_NONE, nullptr, false, lease, netmask, router); +} + bool RnaLogger::log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip, const uint8_t* src_mac, RnaTracker* ht, const Packet* p, uint32_t event_time, uint16_t proto, const HostMac* hm, const HostApplication* ha, const FpFingerprint* fp, void* cond_var, const HostClient* hc, - const char* user, AppId appid, const char* di, bool jb) + const char* user, AppId appid, const char* di, bool jb, uint32_t lease, + uint32_t netmask, const struct in6_addr* router) { if ( !enabled ) return false; @@ -182,7 +204,7 @@ bool RnaLogger::log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ assert(ht); RnaLoggerEvent rle(type, subtype, src_mac, ht, hm, proto, cond_var, - ha, fp, hc, user, appid, di, jb, p); + ha, fp, hc, user, appid, di, jb, lease, netmask, router, p); if ( src_ip and (!IN6_IS_ADDR_V4MAPPED(src_ip) or src_ip->s6_addr32[3]) ) rle.ip = src_ip; else diff --git a/src/network_inspectors/rna/rna_logger.h b/src/network_inspectors/rna/rna_logger.h index 5521ce47b..ec6827254 100644 --- a/src/network_inspectors/rna/rna_logger.h +++ b/src/network_inspectors/rna/rna_logger.h @@ -38,9 +38,11 @@ struct RnaLoggerEvent : public Event RnaLoggerEvent (uint16_t t, uint16_t st, const uint8_t* mc, const RnaTracker* rt, const snort::HostMac* hmp, uint16_t pr, void* cv, const snort::HostApplication* hap, const snort::FpFingerprint* fpr, const snort::HostClient* hcp, const char* u, - int32_t app, const char* di, bool jb, const snort::Packet* p) : type(t), subtype(st), + int32_t app, const char* di, bool jb, uint32_t ls, uint32_t nm, + const struct in6_addr* rtr, const snort::Packet* p) : type(t), subtype(st), mac(mc), ht(rt), hm(hmp), proto(pr), cond_var(cv), ha(hap), fp(fpr), hc(hcp), - user(u), appid(app), device_info(di), jail_broken(jb), pkt(p) { } + user(u), appid(app), device_info(di), jail_broken(jb), lease(ls), netmask(nm), + router(rtr), pkt(p) { } uint32_t event_time = 0; uint16_t type; @@ -58,6 +60,9 @@ struct RnaLoggerEvent : public Event AppId appid; const char* device_info; bool jail_broken; + uint32_t lease; + uint32_t netmask; + const struct in6_addr* router; const snort::Packet* pkt; }; @@ -101,6 +106,11 @@ public: void log(uint16_t type, uint16_t subtype, const snort::Packet* p, const uint8_t* src_mac, const struct in6_addr* src_ip, RnaTracker* ht, uint32_t event_time, void* cond_var); + // for dhcp info event + void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht, + const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t lease, uint32_t netmask, + const struct in6_addr* router); + // for all bool log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip, const uint8_t* src_mac, RnaTracker* ht, const snort::Packet* p = nullptr, @@ -108,7 +118,8 @@ public: const snort::HostApplication* ha = nullptr, const snort::FpFingerprint* fp = nullptr, void* cond_var = nullptr, const snort::HostClient* hc = nullptr, const char* user = nullptr, AppId appid = APP_ID_NONE, const char* device_info = nullptr, - bool jail_broken = false); + bool jail_broken = false, uint32_t lease = 0, uint32_t netmask = 0, + const struct in6_addr* router = nullptr); private: const bool enabled; diff --git a/src/network_inspectors/rna/rna_logger_common.h b/src/network_inspectors/rna/rna_logger_common.h index aee6625f8..2792efeb6 100644 --- a/src/network_inspectors/rna/rna_logger_common.h +++ b/src/network_inspectors/rna/rna_logger_common.h @@ -41,6 +41,7 @@ #define CHANGE_VLAN_TAG 18 #define CHANGE_BANNER_UPDATE 24 #define CHANGE_CLIENT_APP_UPDATE 32 + #define CHANGE_FULL_DHCP_INFO 33 #define RUA_EVENT 1004 #define CHANGE_USER_LOGIN 2 diff --git a/src/network_inspectors/rna/rna_module.cc b/src/network_inspectors/rna/rna_module.cc index 0387ada9c..46d61e97e 100644 --- a/src/network_inspectors/rna/rna_module.cc +++ b/src/network_inspectors/rna/rna_module.cc @@ -39,6 +39,7 @@ #include "rna_fingerprint_tcp.h" #include "rna_fingerprint_ua.h" +#include "rna_fingerprint_udp.h" #include "rna_mac_cache.h" #ifdef UNIT_TEST @@ -82,6 +83,7 @@ bool FpProcReloadTuner::tinit() { set_tcp_fp_processor(mod_conf.tcp_processor); set_ua_fp_processor(mod_conf.ua_processor); + set_udp_fp_processor(mod_conf.udp_processor); return false; // no work to do after this } @@ -286,6 +288,12 @@ static const Parameter rna_fp_params[] = { "device", Parameter::PT_STRING, nullptr, nullptr, "device information" }, + { "dhcp55", Parameter::PT_STRING, nullptr, nullptr, + "dhcp option 55 values" }, + + { "dhcp60", Parameter::PT_STRING, nullptr, nullptr, + "dhcp option 60 values" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -309,6 +317,9 @@ static const Parameter rna_params[] = { "ua_fingerprints", Parameter::PT_LIST, rna_fp_params, nullptr, "list of user agent fingerprints" }, + { "udp_fingerprints", Parameter::PT_LIST, rna_fp_params, nullptr, + "list of udp fingerprints" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -326,6 +337,8 @@ static const PegInfo rna_pegs[] = { CountType::SUM, "tcp_midstream", "count of TCP midstream packets received" }, { CountType::SUM, "other_packets", "count of packets received without session tracking" }, { CountType::SUM, "change_host_update", "count number of change host update events" }, + { CountType::SUM, "dhcp_data", "count of DHCP data events received" }, + { CountType::SUM, "dhcp_info", "count of new DHCP lease events received" }, { CountType::END, nullptr, nullptr}, }; @@ -367,6 +380,12 @@ bool RnaModule::begin(const char* fqn, int, SnortConfig*) if (!mod_conf->ua_processor) mod_conf->ua_processor = new UaFpProcessor; } + else if (!strcmp(fqn, "rna.udp_fingerprints")) + { + fingerprint.clear(); + if (!mod_conf->udp_processor) + mod_conf->udp_processor = new UdpFpProcessor; + } return true; } @@ -386,7 +405,7 @@ bool RnaModule::set(const char* fqn, Value& v, SnortConfig*) dump_file = snort_strdup(v.get_string()); } else if ( fqn and ( strstr(fqn, "rna.tcp_fingerprints") or - strstr(fqn, "rna.ua_fingerprints") ) ) + strstr(fqn, "rna.ua_fingerprints") or strstr(fqn, "rna.udp_fingerprints") ) ) { if (v.is("fpid")) fingerprint.fpid = v.get_uint32(); @@ -423,6 +442,10 @@ bool RnaModule::set(const char* fqn, Value& v, SnortConfig*) return false; fingerprint.user_agent.emplace_back(ua_part); } + else if (v.is("dhcp55")) + fingerprint.dhcp55 = v.get_string(); + else if (v.is("dhcp60")) + fingerprint.dhcp60 = v.get_string(); else return false; } @@ -469,6 +492,11 @@ bool RnaModule::end(const char* fqn, int index, SnortConfig* sc) mod_conf->ua_processor->push(fingerprint); fingerprint.clear(); } + else if ( index > 0 and mod_conf->udp_processor and !strcmp(fqn, "rna.udp_fingerprints") ) + { + mod_conf->udp_processor->push(fingerprint); + fingerprint.clear(); + } return true; } @@ -544,7 +572,8 @@ bool RnaModule::log_mac_cache(const char* outfile) bool RnaModule::is_valid_fqn(const char* fqn) const { return !strcmp(fqn, RNA_NAME) or !strcmp(fqn, "rna.tcp_fingerprints") or - !strcmp(fqn, "rna.ua_fingerprints") or !strcmp(fqn, "rna.ua_fingerprints.user_agent"); + !strcmp(fqn, "rna.ua_fingerprints") or !strcmp(fqn, "rna.ua_fingerprints.user_agent") or + !strcmp(fqn, "rna.udp_fingerprints"); } diff --git a/src/network_inspectors/rna/rna_module.h b/src/network_inspectors/rna/rna_module.h index 4fbcd0bae..a3638b8f1 100644 --- a/src/network_inspectors/rna/rna_module.h +++ b/src/network_inspectors/rna/rna_module.h @@ -44,6 +44,8 @@ struct RnaStats PegCount tcp_midstream; PegCount other_packets; PegCount change_host_update; + PegCount dhcp_data; + PegCount dhcp_info; }; extern THREAD_LOCAL RnaStats rna_stats; diff --git a/src/network_inspectors/rna/rna_pnd.cc b/src/network_inspectors/rna/rna_pnd.cc index 020ccef1a..c63ddeb35 100644 --- a/src/network_inspectors/rna/rna_pnd.cc +++ b/src/network_inspectors/rna/rna_pnd.cc @@ -37,6 +37,7 @@ #include "rna_app_discovery.h" #include "rna_fingerprint_tcp.h" +#include "rna_fingerprint_udp.h" #include "rna_logger_common.h" #ifdef UNIT_TEST @@ -215,6 +216,83 @@ void RnaPnd::discover_network(const Packet* p, uint8_t ttl) } } +void RnaPnd::analyze_dhcp_fingerprint(DataEvent& event) +{ + const Packet* p = event.get_packet(); + const DHCPDataEvent& dhcp_data_event = static_cast(event); + const uint8_t* src_mac = dhcp_data_event.get_eth_addr(); + bool new_host = false; + bool new_mac = false; + const auto& src_ip = p->ptrs.ip_api.get_src(); + auto ht = host_cache.find_else_create(*src_ip, &new_host); + if (!new_host) + ht->update_last_seen(); + + MacKey mk(src_mac); + auto hm_ptr = host_cache_mac.find_else_create(mk, &new_mac); + if (new_mac) + { + ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0); + logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, nullptr, mk.mac_addr); + hm_ptr->update_last_event(p->pkth->ts.tv_sec); + } + else + hm_ptr->update_last_seen(p->pkth->ts.tv_sec); + + const UdpFpProcessor* processor = get_udp_fp_processor(); + if (!processor) + return; + + FpDHCPKey key; + key.dhcp55_len = dhcp_data_event.get_op55_len(); + key.dhcp55 = dhcp_data_event.get_op55(); + key.dhcp60_len = dhcp_data_event.get_op60_len(); + key.dhcp60 = dhcp_data_event.get_op60(); + + const DHCPFingerprint* dhcp_fp = processor->match_dhcp_fingerprint(key); + if (dhcp_fp and ht->add_udp_fingerprint(dhcp_fp->fpid)) + { + const auto& src_ip_ptr = (const struct in6_addr*) src_ip->get_ip6_ptr(); + logger.log(RNA_EVENT_NEW, NEW_OS, p, &ht, src_ip_ptr, src_mac, dhcp_fp, packet_time()); + } +} + +/* called for processing information extracted from DHCP Ack. + It is called only for IPv4 since DHCPv6 is not implemented.*/ +void RnaPnd::add_dhcp_info(DataEvent& event) +{ + const DHCPInfoEvent& dhcp_info_event = static_cast(event); + const uint8_t* src_mac = dhcp_info_event.get_eth_addr(); + uint32_t ip_address = dhcp_info_event.get_ip_address(); + uint32_t net_mask = dhcp_info_event.get_subnet_mask(); + uint32_t lease = dhcp_info_event.get_lease_secs(); + uint32_t router = dhcp_info_event.get_router(); + const Packet* p = event.get_packet(); + + SfIp leased_ip = {(void*)&ip_address, AF_INET}; + SfIp router_ip = {(void*)&router, AF_INET}; + bool new_host = false; + bool new_mac = false; + auto ht = host_cache.find_else_create(leased_ip, &new_host); + if (!new_host) + ht->update_last_seen(); + + MacKey mk(src_mac); + auto hm_ptr = host_cache_mac.find_else_create(mk, &new_mac); + if (new_mac) + { + ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0); + logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, nullptr, mk.mac_addr); + hm_ptr->update_last_event(p->pkth->ts.tv_sec); + } + else + hm_ptr->update_last_seen(p->pkth->ts.tv_sec); + + logger.log(RNA_EVENT_CHANGE, CHANGE_FULL_DHCP_INFO, p, &ht, + (const struct in6_addr*) leased_ip.get_ip6_ptr(), src_mac, + lease, net_mask, (const struct in6_addr*) router_ip.get_ip6_ptr()); +} + inline void RnaPnd::update_vlan(const Packet* p, HostTrackerMac& hm) { if ( !(p->proto_bits & PROTO_BIT__VLAN) ) diff --git a/src/network_inspectors/rna/rna_pnd.h b/src/network_inspectors/rna/rna_pnd.h index 591ddd440..6c70b0a6f 100644 --- a/src/network_inspectors/rna/rna_pnd.h +++ b/src/network_inspectors/rna/rna_pnd.h @@ -30,6 +30,7 @@ #include "protocols/tcp.h" #include "protocols/vlan.h" #include "pub_sub/appid_events.h" +#include "pub_sub/dhcp_events.h" #include "sfip/sf_ip.h" #include "rna_config.h" @@ -126,6 +127,8 @@ public: void analyze_flow_non_ip(const snort::Packet*); void analyze_flow_tcp(const snort::Packet*, TcpPacketType); void analyze_flow_udp(const snort::Packet*); + void analyze_dhcp_fingerprint(snort::DataEvent&); + void add_dhcp_info(snort::DataEvent&); // generate change event for all hosts in the ip cache void generate_change_host_update(); diff --git a/src/network_inspectors/rna/test/rna_module_mock.h b/src/network_inspectors/rna/test/rna_module_mock.h index a80c4c1af..2bf28df52 100644 --- a/src/network_inspectors/rna/test/rna_module_mock.h +++ b/src/network_inspectors/rna/test/rna_module_mock.h @@ -72,6 +72,8 @@ UaFpProcessor::~UaFpProcessor() { } void UaFpProcessor::make_mpse(SnortConfig*) { } void UaFpProcessor::push(RawFingerprint const&) { } +void UdpFpProcessor::push(RawFingerprint const&) { } + // inspector class RnaInspector { diff --git a/src/network_inspectors/rna/test/rna_module_test.cc b/src/network_inspectors/rna/test/rna_module_test.cc index 586adbca2..9a3975950 100644 --- a/src/network_inspectors/rna/test/rna_module_test.cc +++ b/src/network_inspectors/rna/test/rna_module_test.cc @@ -38,6 +38,7 @@ void set_tcp_fp_processor(TcpFpProcessor*) { } void set_ua_fp_processor(UaFpProcessor*) { } +void set_udp_fp_processor(UdpFpProcessor*) { } namespace snort { diff --git a/src/pub_sub/CMakeLists.txt b/src/pub_sub/CMakeLists.txt index fe4a0ccdd..f319a71e8 100644 --- a/src/pub_sub/CMakeLists.txt +++ b/src/pub_sub/CMakeLists.txt @@ -4,6 +4,7 @@ set (PUB_SUB_INCLUDES data_decrypt_event.h daq_message_event.h dcerpc_events.h + dhcp_events.h expect_events.h finalize_packet_event.h http_events.h diff --git a/src/pub_sub/dhcp_events.h b/src/pub_sub/dhcp_events.h new file mode 100644 index 000000000..a6abba364 --- /dev/null +++ b/src/pub_sub/dhcp_events.h @@ -0,0 +1,114 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- +// dhcp_events.h author Sreeja Athirkandathil Narayanan + +#ifndef DHCP_EVENTS_H +#define DHCP_EVENTS_H + +#include +#include "framework/data_bus.h" + +#define DHCP_DATA_EVENT "dhcp_data_event" +#define DHCP_INFO_EVENT "dhcp_info_event" +#define DHCP_OP55_MAX_SIZE 64 +#define DHCP_OP60_MAX_SIZE 64 + +namespace snort +{ + +class DHCPInfoEvent : public snort::DataEvent +{ +public: + DHCPInfoEvent(const snort::Packet* p, uint32_t ip_address, const uint8_t* eth, + uint32_t subnet_mask, uint32_t lease_secs, uint32_t router) : + pkt(p), ip_address(ip_address), subnet_mask(subnet_mask), + lease_secs(lease_secs), router(router) + { + memcpy(eth_addr, eth, sizeof(eth_addr)); + } + + const snort::Packet* get_packet() override + { return pkt; } + + uint32_t get_ip_address() const + { return ip_address; } + + const uint8_t* get_eth_addr() const + { return eth_addr; } + + uint32_t get_subnet_mask() const + { return subnet_mask; } + + uint32_t get_lease_secs() const + { return lease_secs; } + + uint32_t get_router() const + { return router; } + +private: + const snort::Packet* pkt; + uint32_t ip_address; + uint8_t eth_addr[6]; + uint32_t subnet_mask; + uint32_t lease_secs; + uint32_t router; +}; + +class DHCPDataEvent : public snort::DataEvent +{ +public: + DHCPDataEvent(const snort::Packet* p, unsigned op55_len, unsigned op60_len, + const uint8_t* op55_val, const uint8_t* op60_val, const uint8_t* eth) : pkt(p), + op55_len(op55_len), op60_len(op60_len) + { + memcpy(op55, op55_val, op55_len); + if (op60_len) + memcpy(op60, op60_val, op60_len); + memcpy(eth_addr, eth, sizeof(eth_addr)); + } + + const snort::Packet* get_packet() override + { return pkt; } + + unsigned get_op55_len() const + { return op55_len; } + + unsigned get_op60_len() const + { return op60_len; } + + const uint8_t* get_op55() const + { return op55; } + + const uint8_t* get_op60() const + { return op60; } + + const uint8_t* get_eth_addr() const + { return eth_addr; } + +private: + const snort::Packet* pkt; + unsigned op55_len; + unsigned op60_len; + uint8_t op55[DHCP_OP55_MAX_SIZE] = {0}; + uint8_t op60[DHCP_OP60_MAX_SIZE] = {0}; + uint8_t eth_addr[6]; +}; + +} + +#endif // DHCP_EVENTS_H