diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index a111d36c4f..1d86a7bed8 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -11,7 +11,6 @@ #include "zeek/analyzer/protocol/pia/PIA.h" #include "zeek/analyzer/protocol/stepping-stone/SteppingStone.h" #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" #include "zeek/plugin/Manager.h" @@ -375,13 +374,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) DBG_ANALYZER(conn, "activated TCP analyzer"); break; - case TRANSPORT_UDP: - root = new analyzer::udp::UDP_Analyzer(conn); - pia = new analyzer::pia::PIA_UDP(conn); - check_port = true; - DBG_ANALYZER(conn, "activated UDP analyzer"); - break; - default: reporter->InternalWarning("unknown protocol can't build analyzer tree"); return false; diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 1a6e241ece..0d628ded1d 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -44,7 +44,6 @@ add_subdirectory(stepping-stone) add_subdirectory(syslog) add_subdirectory(tcp) add_subdirectory(teredo) -add_subdirectory(udp) add_subdirectory(vxlan) add_subdirectory(xmpp) add_subdirectory(zip) diff --git a/src/analyzer/protocol/dhcp/DHCP.h b/src/analyzer/protocol/dhcp/DHCP.h index dbe13d4df7..8ae911ae44 100644 --- a/src/analyzer/protocol/dhcp/DHCP.h +++ b/src/analyzer/protocol/dhcp/DHCP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "analyzer/protocol/dhcp/dhcp_pac.h" namespace zeek::analyzer::dhcp { diff --git a/src/analyzer/protocol/dnp3/DNP3.h b/src/analyzer/protocol/dnp3/DNP3.h index 3fe5d1e9f0..6540be39d6 100644 --- a/src/analyzer/protocol/dnp3/DNP3.h +++ b/src/analyzer/protocol/dnp3/DNP3.h @@ -1,7 +1,6 @@ #pragma once #include "zeek/analyzer/protocol/tcp/TCP.h" -#include "zeek/analyzer/protocol/udp/UDP.h" #include "analyzer/protocol/dnp3/dnp3_pac.h" diff --git a/src/analyzer/protocol/netbios/NetbiosSSN.h b/src/analyzer/protocol/netbios/NetbiosSSN.h index f73631f435..a3a97728e2 100644 --- a/src/analyzer/protocol/netbios/NetbiosSSN.h +++ b/src/analyzer/protocol/netbios/NetbiosSSN.h @@ -2,7 +2,6 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" namespace zeek::analyzer::netbios_ssn { diff --git a/src/analyzer/protocol/ntp/NTP.h b/src/analyzer/protocol/ntp/NTP.h index 0e829f9288..9d2fcb07b1 100644 --- a/src/analyzer/protocol/ntp/NTP.h +++ b/src/analyzer/protocol/ntp/NTP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ntp/events.bif.h" #include "zeek/analyzer/protocol/ntp/types.bif.h" #include "zeek/analyzer/protocol/ntp/ntp_pac.h" diff --git a/src/analyzer/protocol/radius/RADIUS.h b/src/analyzer/protocol/radius/RADIUS.h index 1e1648c84f..7ab093e073 100644 --- a/src/analyzer/protocol/radius/RADIUS.h +++ b/src/analyzer/protocol/radius/RADIUS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/radius/events.bif.h" #include "zeek/analyzer/protocol/radius/radius_pac.h" diff --git a/src/analyzer/protocol/rdp/RDPEUDP.h b/src/analyzer/protocol/rdp/RDPEUDP.h index 13c5651633..01f2326adb 100644 --- a/src/analyzer/protocol/rdp/RDPEUDP.h +++ b/src/analyzer/protocol/rdp/RDPEUDP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/rdp/events.bif.h" #include "zeek/analyzer/protocol/rdp/rdpeudp_pac.h" diff --git a/src/analyzer/protocol/sip/SIP.h b/src/analyzer/protocol/sip/SIP.h index 18ec010a8b..15fe1371f3 100644 --- a/src/analyzer/protocol/sip/SIP.h +++ b/src/analyzer/protocol/sip/SIP.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/sip/events.bif.h" #include "zeek/analyzer/protocol/sip/sip_pac.h" diff --git a/src/analyzer/protocol/ssl/DTLS.h b/src/analyzer/protocol/ssl/DTLS.h index 1554c1bb6e..121af08cde 100644 --- a/src/analyzer/protocol/ssl/DTLS.h +++ b/src/analyzer/protocol/ssl/DTLS.h @@ -1,7 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" - #include "zeek/analyzer/protocol/ssl/events.bif.h" namespace binpac { namespace DTLS { class SSL_Conn; } } diff --git a/src/analyzer/protocol/syslog/Syslog.h b/src/analyzer/protocol/syslog/Syslog.h index d1aea12d05..941492a96c 100644 --- a/src/analyzer/protocol/syslog/Syslog.h +++ b/src/analyzer/protocol/syslog/Syslog.h @@ -1,6 +1,5 @@ #pragma once -#include "zeek/analyzer/protocol/udp/UDP.h" #include "zeek/analyzer/protocol/tcp/TCP.h" #include "analyzer/protocol/syslog/syslog_pac.h" diff --git a/src/analyzer/protocol/udp/CMakeLists.txt b/src/analyzer/protocol/udp/CMakeLists.txt deleted file mode 100644 index 47140a9df2..0000000000 --- a/src/analyzer/protocol/udp/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -include(ZeekPlugin) - -include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - -zeek_plugin_begin(Zeek UDP) -zeek_plugin_cc(UDP.cc Plugin.cc) -zeek_plugin_bif(events.bif) -zeek_plugin_end() diff --git a/src/analyzer/protocol/udp/Plugin.cc b/src/analyzer/protocol/udp/Plugin.cc deleted file mode 100644 index fc08de2eb3..0000000000 --- a/src/analyzer/protocol/udp/Plugin.cc +++ /dev/null @@ -1,22 +0,0 @@ -// See the file in the main distribution directory for copyright. - -#include "zeek/plugin/Plugin.h" -#include "zeek/analyzer/Component.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -namespace zeek::plugin::detail::Zeek_UDP { - -class Plugin : public zeek::plugin::Plugin { -public: - zeek::plugin::Configuration Configure() override - { - AddComponent(new zeek::analyzer::Component("UDP", zeek::analyzer::udp::UDP_Analyzer::Instantiate)); - - zeek::plugin::Configuration config; - config.name = "Zeek::UDP"; - config.description = "UDP Analyzer"; - return config; - } -} plugin; - -} // namespace zeek::plugin::detail::Zeek_UDP diff --git a/src/analyzer/protocol/udp/UDP.cc b/src/analyzer/protocol/udp/UDP.cc deleted file mode 100644 index e29f14d251..0000000000 --- a/src/analyzer/protocol/udp/UDP.cc +++ /dev/null @@ -1,275 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#include "zeek/zeek-config.h" -#include "zeek/analyzer/protocol/udp/UDP.h" - -#include - -#include "zeek/RunState.h" -#include "zeek/NetVar.h" -#include "zeek/analyzer/Manager.h" -#include "zeek/Reporter.h" -#include "zeek/Conn.h" - -#include "zeek/analyzer/protocol/udp/events.bif.h" - -namespace zeek::analyzer::udp { - -UDP_Analyzer::UDP_Analyzer(Connection* conn) - : analyzer::TransportLayerAnalyzer("UDP", conn) - { - conn->EnableStatusUpdateTimer(); - conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); - request_len = reply_len = -1; // -1 means "haven't seen any activity" - - req_chk_cnt = rep_chk_cnt = 0; - req_chk_thresh = rep_chk_thresh = 1; - } - -UDP_Analyzer::~UDP_Analyzer() - { - // XXX: need to implement this! - // delete src_pkt_writer; - } - -void UDP_Analyzer::Init() - { - } - -void UDP_Analyzer::Done() - { - Analyzer::Done(); - } - -void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, - uint64_t seq, const IP_Hdr* ip, int caplen) - { - assert(ip); - - Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen); - - const struct udphdr* up = (const struct udphdr*) data; - - // Increment data before checksum check so that data will - // point to UDP payload even if checksum fails. Particularly, - // it allows event packet_contents to get to the data. - data += sizeof(struct udphdr); - - // We need the min() here because Ethernet frame padding can lead to - // caplen > len. - if ( packet_contents ) - PacketContents(data, std::min(len, caplen) - sizeof(struct udphdr)); - - int chksum = up->uh_sum; - - auto validate_checksum = - ! run_state::current_pkt->l3_checksummed && - ! zeek::detail::ignore_checksums && - ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && - caplen >=len; - - constexpr auto vxlan_len = 8; - constexpr auto eth_len = 14; - - if ( validate_checksum && - len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && - (data[0] & 0x08) == 0x08 ) - { - auto& vxlan_ports = analyzer_mgr->GetVxlanPorts(); - - if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), - ntohs(up->uh_dport)) != vxlan_ports.end() ) - { - // Looks like VXLAN on a well-known port, so the checksum should be - // transmitted as zero, and we should accept that. If not - // transmitted as zero, then validating the checksum is optional. - if ( chksum == 0 ) - validate_checksum = false; - else - validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; - } - } - - if ( validate_checksum ) - { - bool bad = false; - - if ( ip->IP4_Hdr() ) - { - if ( chksum && ! ValidateChecksum(ip, up, len) ) - bad = true; - } - - /* checksum is not optional for IPv6 */ - else if ( ! ValidateChecksum(ip, up, len) ) - bad = true; - - if ( bad ) - { - Weird("bad_UDP_checksum"); - - if ( is_orig ) - { - uint32_t t = req_chk_thresh; - if ( Conn()->ScaledHistoryEntry('C', req_chk_cnt, - req_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - else - { - uint32_t t = rep_chk_thresh; - if ( Conn()->ScaledHistoryEntry('c', rep_chk_cnt, - rep_chk_thresh) ) - ChecksumEvent(is_orig, t); - } - - return; - } - } - - int ulen = ntohs(up->uh_ulen); - if ( ulen != len ) - Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); - - len -= sizeof(struct udphdr); - ulen -= sizeof(struct udphdr); - caplen -= sizeof(struct udphdr); - - Conn()->SetLastTime(run_state::current_timestamp); - - if ( udp_contents ) - { - static auto udp_content_ports = id::find_val("udp_content_ports"); - static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); - static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); - bool do_udp_contents = false; - const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); - const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); - - if ( udp_content_ports->FindOrDefault(dport_val) || - udp_content_ports->FindOrDefault(sport_val) ) - do_udp_contents = true; - else - { - uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? Conn()->RespPort() - : up->uh_dport; - const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); - - if ( is_orig ) - { - auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) - do_udp_contents = true; - } - else - { - auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); - - if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) - do_udp_contents = true; - } - } - - if ( do_udp_contents ) - EnqueueConnEvent(udp_contents, - ConnVal(), - val_mgr->Bool(is_orig), - make_intrusive(len, (const char*) data)); - } - - if ( is_orig ) - { - Conn()->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); - - if ( request_len < 0 ) - request_len = ulen; - else - { - request_len += ulen; -#ifdef DEBUG - if ( request_len < 0 ) - reporter->Warning("wrapping around for UDP request length"); -#endif - } - - Event(udp_request); - } - - else - { - Conn()->CheckHistory(HIST_RESP_DATA_PKT, 'd'); - - if ( reply_len < 0 ) - reply_len = ulen; - else - { - reply_len += ulen; -#ifdef DEBUG - if ( reply_len < 0 ) - reporter->Warning("wrapping around for UDP reply length"); -#endif - } - - Event(udp_reply); - } - - if ( caplen >= len ) - ForwardPacket(len, data, is_orig, seq, ip, caplen); - } - -void UDP_Analyzer::UpdateConnVal(RecordVal* conn_val) - { - auto orig_endp = conn_val->GetFieldAs("orig"); - auto resp_endp = conn_val->GetFieldAs("resp"); - - UpdateEndpointVal(orig_endp, true); - UpdateEndpointVal(resp_endp, false); - - // Call children's UpdateConnVal - Analyzer::UpdateConnVal(conn_val); - } - -void UDP_Analyzer::UpdateEndpointVal(RecordVal* endp, bool is_orig) - { - bro_int_t size = is_orig ? request_len : reply_len; - if ( size < 0 ) - { - endp->Assign(0, 0); - endp->Assign(1, UDP_INACTIVE); - } - - else - { - endp->Assign(0, static_cast(size)); - endp->Assign(1, UDP_ACTIVE); - } - } - -bool UDP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */) - { - return false; - } - -unsigned int UDP_Analyzer::MemoryAllocation() const - { - // A rather low lower bound.... - return Analyzer::MemoryAllocation() + padded_sizeof(*this) - 24; - } - -void UDP_Analyzer::ChecksumEvent(bool is_orig, uint32_t threshold) - { - Conn()->HistoryThresholdEvent(udp_multiple_checksum_errors, - is_orig, threshold); - } - -bool UDP_Analyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) - { - auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), - IPPROTO_UDP, - reinterpret_cast(up), len); - - return sum == 0xffff; - } - -} // namespace zeek::analyzer::udp diff --git a/src/analyzer/protocol/udp/UDP.h b/src/analyzer/protocol/udp/UDP.h deleted file mode 100644 index 1a1ef94e62..0000000000 --- a/src/analyzer/protocol/udp/UDP.h +++ /dev/null @@ -1,57 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#pragma once - -// This will include netinet/udp.h for us, plus set up some defines that make it work on all -// of the CI platforms. -#include "zeek/net_util.h" - -#include "zeek/analyzer/Analyzer.h" - -namespace zeek::analyzer::udp { - -enum UDP_EndpointState { - UDP_INACTIVE, // no packet seen - UDP_ACTIVE, // packets seen -}; - -class UDP_Analyzer final : public analyzer::TransportLayerAnalyzer { -public: - explicit UDP_Analyzer(Connection* conn); - ~UDP_Analyzer() override; - - void Init() override; - void UpdateConnVal(RecordVal *conn_val) override; - - static analyzer::Analyzer* Instantiate(Connection* conn) - { return new UDP_Analyzer(conn); } - -protected: - void Done() override; - void DeliverPacket(int len, const u_char* data, bool orig, - uint64_t seq, const IP_Hdr* ip, int caplen) override; - bool IsReuse(double t, const u_char* pkt) override; - unsigned int MemoryAllocation() const override; - - void ChecksumEvent(bool is_orig, uint32_t threshold); - - // Returns true if the checksum is valid, false if not - static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, - int len); - - bro_int_t request_len, reply_len; - -private: - void UpdateEndpointVal(RecordVal* endp, bool is_orig); - -#define HIST_ORIG_DATA_PKT 0x1 -#define HIST_RESP_DATA_PKT 0x2 -#define HIST_ORIG_CORRUPT_PKT 0x4 -#define HIST_RESP_CORRUPT_PKT 0x8 - - // For tracking checksum history. - uint32_t req_chk_cnt, req_chk_thresh; - uint32_t rep_chk_cnt, rep_chk_thresh; -}; - -} // namespace zeek::analyzer::udp diff --git a/src/packet_analysis/protocol/udp/CMakeLists.txt b/src/packet_analysis/protocol/udp/CMakeLists.txt index 5e205c57f1..47140a9df2 100644 --- a/src/packet_analysis/protocol/udp/CMakeLists.txt +++ b/src/packet_analysis/protocol/udp/CMakeLists.txt @@ -3,6 +3,7 @@ include(ZeekPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) -zeek_plugin_begin(PacketAnalyzer UDP_PKT) +zeek_plugin_begin(Zeek UDP) zeek_plugin_cc(UDP.cc Plugin.cc) +zeek_plugin_bif(events.bif) zeek_plugin_end() diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index 4bbe7d737d..7c77be6fc5 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -12,9 +12,11 @@ public: { AddComponent(new zeek::packet_analysis::Component("UDP", zeek::packet_analysis::UDP::UDPAnalyzer::Instantiate)); + AddComponent(new zeek::analyzer::Component("UDP", + zeek::packet_analysis::UDP::UDPTransportAnalyzer::Instantiate)); zeek::plugin::Configuration config; - config.name = "Zeek::UDP_PKT"; + config.name = "Zeek::UDP"; config.description = "Packet analyzer for UDP"; return config; } diff --git a/src/packet_analysis/protocol/udp/UDP.cc b/src/packet_analysis/protocol/udp/UDP.cc index f17e1280dd..d7d5cbe6e5 100644 --- a/src/packet_analysis/protocol/udp/UDP.cc +++ b/src/packet_analysis/protocol/udp/UDP.cc @@ -2,12 +2,31 @@ #include "zeek/packet_analysis/protocol/udp/UDP.h" #include "zeek/RunState.h" +#include "zeek/Conn.h" +#include "zeek/session/Manager.h" +#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/analyzer/protocol/conn-size/ConnSize.h" + +#include "zeek/packet_analysis/protocol/udp/events.bif.h" using namespace zeek::packet_analysis::UDP; using namespace zeek::packet_analysis::IP; +constexpr uint32_t HIST_ORIG_DATA_PKT = 0x1; +constexpr uint32_t HIST_RESP_DATA_PKT = 0x2; +constexpr uint32_t HIST_ORIG_CORRUPT_PKT = 0x4; +constexpr uint32_t HIST_RESP_CORRUPT_PKT = 0x8; + +enum UDP_EndpointState { + UDP_INACTIVE, // no packet seen + UDP_ACTIVE, // packets seen +}; + UDPAnalyzer::UDPAnalyzer() : IPBasedAnalyzer("UDP", TRANSPORT_UDP, UDP_PORT_MASK, false) { + // TODO: remove once the other plugins are done + new_plugin = true; } UDPAnalyzer::~UDPAnalyzer() @@ -33,9 +52,34 @@ bool UDPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) return true; } + void UDPAnalyzer::CreateTransportAnalyzer(Connection* conn, IPBasedTransportAnalyzer*& root, analyzer::pia::PIA*& pia, bool& check_port) { + root = new UDPTransportAnalyzer(conn); + root->SetParent(this); + + conn->EnableStatusUpdateTimer(); + conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout); + + pia = new analyzer::pia::PIA_UDP(conn); + check_port = true; + } + +void UDPAnalyzer::Initialize() + { + IPBasedAnalyzer::Initialize(); + + const auto& id = detail::global_scope()->Find("Tunnel::vxlan_ports"); + + if ( ! (id && id->GetVal()) ) + reporter->FatalError("Tunnel::vxlan_ports not defined"); + + auto table_val = id->GetVal()->AsTableVal(); + auto port_list = table_val->ToPureListVal(); + + for ( auto i = 0; i < port_list->Length(); ++i ) + vxlan_ports.emplace_back(port_list->Idx(i)->AsPortVal()->Port()); } bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, @@ -44,3 +88,253 @@ bool UDPAnalyzer::WantConnection(uint16_t src_port, uint16_t dst_port, flip_roles = IsLikelyServerPort(src_port) && ! IsLikelyServerPort(dst_port); return true; } + +void UDPAnalyzer::ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, Packet* pkt) + { + conn = c; + + auto* ta = static_cast(conn->GetRootAnalyzer()); + + const u_char* data = pkt->ip_hdr->Payload(); + int len = pkt->ip_hdr->PayloadLen(); + + const struct udphdr* up = (const struct udphdr*) data; + const std::unique_ptr& ip = pkt->ip_hdr; + + ta->DeliverPacket(len, data, is_orig, -1, ip.get(), remaining); + + // Increment data before checksum check so that data will + // point to UDP payload even if checksum fails. Particularly, + // it allows event packet_contents to get to the data. + data += sizeof(struct udphdr); + + // We need the min() here because Ethernet frame padding can lead to + // remaining > len. + if ( packet_contents ) + ta->PacketContents(data, std::min(len, remaining) - sizeof(struct udphdr)); + + int chksum = up->uh_sum; + + auto validate_checksum = + ! run_state::current_pkt->l3_checksummed && + ! zeek::detail::ignore_checksums && + ! zeek::id::find_val("ignore_checksums_nets")->Contains(ip->IPHeaderSrcAddr()) && + remaining >=len; + + constexpr auto vxlan_len = 8; + constexpr auto eth_len = 14; + + if ( validate_checksum && + len > ((int)sizeof(struct udphdr) + vxlan_len + eth_len) && + (data[0] & 0x08) == 0x08 ) + { + if ( std::find(vxlan_ports.begin(), vxlan_ports.end(), + ntohs(up->uh_dport)) != vxlan_ports.end() ) + { + // Looks like VXLAN on a well-known port, so the checksum should be + // transmitted as zero, and we should accept that. If not + // transmitted as zero, then validating the checksum is optional. + if ( chksum == 0 ) + validate_checksum = false; + else + validate_checksum = BifConst::Tunnel::validate_vxlan_checksums; + } + } + + if ( validate_checksum ) + { + bool bad = false; + + if ( ip->IP4_Hdr() ) + { + if ( chksum && ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + } + + /* checksum is not optional for IPv6 */ + else if ( ! ValidateChecksum(ip.get(), up, len) ) + bad = true; + + if ( bad ) + { + ta->Weird("bad_UDP_checksum"); + + if ( is_orig ) + { + uint32_t t = ta->req_chk_thresh; + + if ( conn->ScaledHistoryEntry('C', + ta->req_chk_cnt, + ta->req_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + else + { + uint32_t t = ta->rep_chk_thresh; + + if ( conn->ScaledHistoryEntry('c', + ta->rep_chk_cnt, + ta->rep_chk_thresh) ) + ChecksumEvent(is_orig, t); + } + + return; + } + } + + int ulen = ntohs(up->uh_ulen); + if ( ulen != len ) + ta->Weird("UDP_datagram_length_mismatch", util::fmt("%d != %d", ulen, len)); + + len -= sizeof(struct udphdr); + ulen -= sizeof(struct udphdr); + remaining -= sizeof(struct udphdr); + + conn->SetLastTime(run_state::current_timestamp); + + if ( udp_contents ) + { + static auto udp_content_ports = id::find_val("udp_content_ports"); + static auto udp_content_delivery_ports_orig = id::find_val("udp_content_delivery_ports_orig"); + static auto udp_content_delivery_ports_resp = id::find_val("udp_content_delivery_ports_resp"); + bool do_udp_contents = false; + const auto& sport_val = val_mgr->Port(ntohs(up->uh_sport), TRANSPORT_UDP); + const auto& dport_val = val_mgr->Port(ntohs(up->uh_dport), TRANSPORT_UDP); + + if ( udp_content_ports->FindOrDefault(dport_val) || + udp_content_ports->FindOrDefault(sport_val) ) + do_udp_contents = true; + else + { + uint16_t p = zeek::detail::udp_content_delivery_ports_use_resp ? conn->RespPort() + : up->uh_dport; + const auto& port_val = zeek::val_mgr->Port(ntohs(p), TRANSPORT_UDP); + + if ( is_orig ) + { + auto result = udp_content_delivery_ports_orig->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_orig || (result && result->AsBool()) ) + do_udp_contents = true; + } + else + { + auto result = udp_content_delivery_ports_resp->FindOrDefault(port_val); + + if ( zeek::detail::udp_content_deliver_all_resp || (result && result->AsBool()) ) + do_udp_contents = true; + } + } + + if ( do_udp_contents ) + ta->EnqueueConnEvent(udp_contents, + ta->ConnVal(), + val_mgr->Bool(is_orig), + make_intrusive(len, (const char*) data)); + } + + if ( is_orig ) + { + conn->CheckHistory(HIST_ORIG_DATA_PKT, 'D'); + ta->UpdateLength(is_orig, ulen); + ta->Event(udp_request); + } + else + { + conn->CheckHistory(HIST_RESP_DATA_PKT, 'd'); + ta->UpdateLength(is_orig, ulen); + ta->Event(udp_reply); + } + + // Send the packet back into the packet analysis framework. + ForwardPacket(len, data, pkt); + + // Also try sending it into session analysis. + if ( remaining >= len ) + ta->ForwardPacket(len, data, is_orig, -1, ip.get(), remaining); + + conn = nullptr; + } + +bool UDPAnalyzer::ValidateChecksum(const IP_Hdr* ip, const udphdr* up, int len) + { + auto sum = detail::ip_in_cksum(ip->IP4_Hdr(), ip->SrcAddr(), ip->DstAddr(), + IPPROTO_UDP, + reinterpret_cast(up), len); + + return sum == 0xffff; + } + +void UDPAnalyzer::ChecksumEvent(bool is_orig, uint32_t threshold) + { + conn->HistoryThresholdEvent(udp_multiple_checksum_errors, is_orig, threshold); + } + +void UDPTransportAnalyzer::AddExtraAnalyzers(Connection* conn) + { + static analyzer::Tag analyzer_connsize = analyzer_mgr->GetComponentTag("CONNSIZE"); + + if ( analyzer_mgr->IsEnabled(analyzer_connsize) ) + // Add ConnSize analyzer. Needs to see packets, not stream. + AddChildAnalyzer(new analyzer::conn_size::ConnSize_Analyzer(conn)); + } + +void UDPTransportAnalyzer::UpdateConnVal(RecordVal* conn_val) + { + auto orig_endp = conn_val->GetField("orig"); + auto resp_endp = conn_val->GetField("resp"); + + UpdateEndpointVal(orig_endp, true); + UpdateEndpointVal(resp_endp, false); + + // Call children's UpdateConnVal + Analyzer::UpdateConnVal(conn_val); + } + +void UDPTransportAnalyzer::UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig) + { + bro_int_t size = is_orig ? request_len : reply_len; + auto endp = endp_arg->AsRecordVal(); + + if ( size < 0 ) + { + endp->Assign(0, val_mgr->Count(0)); + endp->Assign(1, UDP_INACTIVE); + } + + else + { + endp->Assign(0, static_cast(size)); + endp->Assign(1, UDP_ACTIVE); + } + } + +void UDPTransportAnalyzer::UpdateLength(bool is_orig, int len) + { + if ( is_orig ) + { + if ( request_len < 0 ) + request_len = len; + else + { + request_len += len; +#ifdef DEBUG + if ( request_len < 0 ) + reporter->Warning("wrapping around for UDP request length"); +#endif + } + } + else + { + if ( reply_len < 0 ) + reply_len = len; + else + { + reply_len += len; +#ifdef DEBUG + if ( reply_len < 0 ) + reporter->Warning("wrapping around for UDP reply length"); +#endif + } + } + } diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 2730ece1dd..b8c3a2ae18 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -8,7 +8,7 @@ namespace zeek::packet_analysis::UDP { -class UDPAnalyzer : public IP::IPBasedAnalyzer { +class UDPAnalyzer final : public IP::IPBasedAnalyzer { public: UDPAnalyzer(); ~UDPAnalyzer() override; @@ -23,6 +23,13 @@ public: void CreateTransportAnalyzer(Connection* conn, IP::IPBasedTransportAnalyzer*& root, analyzer::pia::PIA*& pia, bool& check_port) override; + /** + * Initialize the analyzer. This method is called after the configuration + * was read. Derived classes can override this method to implement custom + * initialization. + */ + void Initialize() override; + protected: /** @@ -39,6 +46,54 @@ protected: */ bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data, bool& flip_roles) const override; + + void ContinueProcessing(Connection* c, double t, bool is_orig, int remaining, + Packet* pkt) override; + +private: + + // Returns true if the checksum is valid, false if not + static bool ValidateChecksum(const IP_Hdr* ip, const struct udphdr* up, + int len); + + void ChecksumEvent(bool is_orig, uint32_t threshold); + + Connection* conn; + + std::vector vxlan_ports; +}; + +class UDPTransportAnalyzer final : public IP::IPBasedTransportAnalyzer { + +public: + + UDPTransportAnalyzer(Connection* conn) : + IP::IPBasedTransportAnalyzer("UDP", conn) { } + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) + { + return new UDPTransportAnalyzer(conn); + } + + void AddExtraAnalyzers(Connection* conn) override; + void UpdateConnVal(RecordVal* conn_val) override; + + void UpdateLength(bool is_orig, int len); + + // For tracking checksum history. These are connection-specific so they + // need to be stored in the transport analyzer created for each + // connection. + uint32_t req_chk_cnt = 0; + uint32_t req_chk_thresh = 1; + uint32_t rep_chk_cnt = 0; + uint32_t rep_chk_thresh = 1; + +private: + + void UpdateEndpointVal(const ValPtr& endp_arg, bool is_orig); + + bro_int_t request_len = -1; + bro_int_t reply_len = -1; }; } diff --git a/src/analyzer/protocol/udp/events.bif b/src/packet_analysis/protocol/udp/events.bif similarity index 100% rename from src/analyzer/protocol/udp/events.bif rename to src/packet_analysis/protocol/udp/events.bif diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index adcb56753d..95228fc7ea 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -206,10 +206,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 0ad2f4a685..4ebc37ef20 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -206,10 +206,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek build/scripts/base/bif/plugins/Zeek_Teredo.events.bif.zeek - build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_VXLAN.events.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ICMP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileEntropy.events.bif.zeek build/scripts/base/bif/plugins/Zeek_FileExtract.events.bif.zeek