mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 17:48:21 +00:00
Move ARP analysis into packet analyzer.
This commit is contained in:
parent
0ec7516602
commit
24babf096e
17 changed files with 238 additions and 368 deletions
|
@ -1,3 +1,4 @@
|
|||
|
||||
include(ZeekSubdir)
|
||||
|
||||
include_directories(BEFORE
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "ARP.h"
|
||||
#include "Event.h"
|
||||
|
||||
#include "events.bif.h"
|
||||
|
||||
#include "zeek-config.h"
|
||||
#ifdef HAVE_NET_ETHERNET_H
|
||||
#include <net/ethernet.h>
|
||||
#elif defined(HAVE_SYS_ETHERNET_H)
|
||||
#include <sys/ethernet.h>
|
||||
#elif defined(HAVE_NETINET_IF_ETHER_H)
|
||||
#include <netinet/if_ether.h>
|
||||
#elif defined(HAVE_NET_ETHERTYPES_H)
|
||||
#include <net/ethertypes.h>
|
||||
#endif
|
||||
|
||||
using namespace zeek::packet_analysis::ARP;
|
||||
|
||||
|
@ -9,11 +23,202 @@ ARPAnalyzer::ARPAnalyzer()
|
|||
{
|
||||
}
|
||||
|
||||
// Argh! FreeBSD and Linux have almost completely different net/if_arp.h .
|
||||
// ... and on Solaris we are missing half of the ARPOP codes, so define
|
||||
// them here as necessary:
|
||||
|
||||
#ifndef ARPOP_REQUEST
|
||||
#define ARPOP_REQUEST 1 // ARP request.
|
||||
#endif
|
||||
#ifndef ARPOP_REPLY
|
||||
#define ARPOP_REPLY 2 // ARP reply.
|
||||
#endif
|
||||
#ifndef ARPOP_PREQUEST
|
||||
#define ARPOP_RREQUEST 3 // RARP request.
|
||||
#endif
|
||||
#ifndef ARPOP_RREPLY
|
||||
#define ARPOP_RREPLY 4 // RARP reply.
|
||||
#endif
|
||||
#ifndef ARPOP_InREQUEST
|
||||
#define ARPOP_InREQUEST 8 // InARP request.
|
||||
#endif
|
||||
#ifndef ARPOP_InREPLY
|
||||
#define ARPOP_InREPLY 9 // InARP reply.
|
||||
#endif
|
||||
#ifndef ARPOP_NAK
|
||||
#define ARPOP_NAK 10 // (ATM)ARP NAK.
|
||||
#endif
|
||||
|
||||
#ifndef ar_sha
|
||||
#define ar_sha(ap) ((caddr_t((ap)+1)) + 0)
|
||||
#endif
|
||||
|
||||
#ifndef ar_spa
|
||||
#define ar_spa(ap) ((caddr_t((ap)+1)) + (ap)->ar_hln)
|
||||
#endif
|
||||
|
||||
#ifndef ar_tha
|
||||
#define ar_tha(ap) ((caddr_t((ap)+1)) + (ap)->ar_hln + (ap)->ar_pln)
|
||||
#endif
|
||||
|
||||
#ifndef ar_tpa
|
||||
#define ar_tpa(ap) ((caddr_t((ap)+1)) + 2*(ap)->ar_hln + (ap)->ar_pln)
|
||||
#endif
|
||||
|
||||
#ifndef ARPOP_REVREQUEST
|
||||
#define ARPOP_REVREQUEST ARPOP_RREQUEST
|
||||
#endif
|
||||
|
||||
#ifndef ARPOP_REVREPLY
|
||||
#define ARPOP_REVREPLY ARPOP_RREPLY
|
||||
#endif
|
||||
|
||||
#ifndef ARPOP_INVREQUEST
|
||||
#define ARPOP_INVREQUEST ARPOP_InREQUEST
|
||||
#endif
|
||||
|
||||
#ifndef ARPOP_INVREPLY
|
||||
#define ARPOP_INVREPLY ARPOP_InREPLY
|
||||
#endif
|
||||
|
||||
zeek::packet_analysis::AnalyzerResult ARPAnalyzer::Analyze(Packet* packet, const uint8_t*& data)
|
||||
{
|
||||
// TODO: Make ARP analyzer a native packet analyzer
|
||||
packet->l3_proto = L3_ARP;
|
||||
|
||||
// Check whether the packet is OK ("inspired" in tcpdump's print-arp.c).
|
||||
auto ah = (const struct arp_pkthdr*) data;
|
||||
|
||||
// Check the size.
|
||||
auto min_length = (ar_tpa(ah) - (char*) data) + ah->ar_pln;
|
||||
auto pkt_hdr_len = data - packet->data;
|
||||
auto real_length = packet->cap_len - pkt_hdr_len;
|
||||
if ( min_length > real_length )
|
||||
{
|
||||
packet->Weird("truncated_ARP");
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
|
||||
// Check the address description fields.
|
||||
switch ( ntohs(ah->ar_hrd) ) {
|
||||
case ARPHRD_ETHER:
|
||||
if ( ah->ar_hln != 6 )
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "corrupt-arp-header (hrd=%i, hln=%i)",
|
||||
ntohs(ah->ar_hrd), ah->ar_hln);
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah, "unknown-arp-hw-address (hrd=%i)", ntohs(ah->ar_hrd));
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We don't support IPv6 addresses.
|
||||
switch ( ntohs(ah->ar_pro) ) {
|
||||
case ETHERTYPE_IP:
|
||||
if ( ah->ar_pln != 4 )
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah,"corrupt-arp-header (pro=%i, pln=%i)",
|
||||
ntohs(ah->ar_pro), ah->ar_pln);
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// don't know how to proceed
|
||||
BadARPEvent(ah,"unknown-arp-proto-address (pro=%i)", ntohs(ah->ar_pro));
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check MAC src address = ARP sender MAC address.
|
||||
if ( memcmp(packet->l2_src, ar_sha(ah), ah->ar_hln) != 0 )
|
||||
{
|
||||
BadARPEvent(ah, "weird-arp-sha");
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
|
||||
// Check the code is supported.
|
||||
switch ( ntohs(ah->ar_op) ) {
|
||||
case ARPOP_REQUEST:
|
||||
RequestReplyEvent(arp_request, packet->l2_src, packet->l2_dst,
|
||||
ar_spa(ah), ar_sha(ah), ar_tpa(ah), ar_tha(ah));
|
||||
break;
|
||||
|
||||
case ARPOP_REPLY:
|
||||
RequestReplyEvent(arp_reply, packet->l2_src, packet->l2_dst,
|
||||
ar_spa(ah), ar_sha(ah), ar_tpa(ah), ar_tha(ah));
|
||||
break;
|
||||
|
||||
case ARPOP_REVREQUEST:
|
||||
case ARPOP_REVREPLY:
|
||||
case ARPOP_INVREQUEST:
|
||||
case ARPOP_INVREPLY:
|
||||
{
|
||||
// don't know how to handle the opcode
|
||||
BadARPEvent(ah, "unimplemented-arp-opcode (%i)", ntohs(ah->ar_op));
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// invalid opcode
|
||||
BadARPEvent(ah, "invalid-arp-opcode (opcode=%i)", ntohs(ah->ar_op));
|
||||
return AnalyzerResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Leave packet analyzer land
|
||||
return AnalyzerResult::Terminate;
|
||||
}
|
||||
|
||||
zeek::AddrValPtr ARPAnalyzer::ToAddrVal(const void* addr)
|
||||
{
|
||||
//Note: We only handle IPv4 addresses.
|
||||
return zeek::make_intrusive<zeek::AddrVal>(*(const uint32_t*) addr);
|
||||
}
|
||||
|
||||
zeek::StringValPtr ARPAnalyzer::ToEthAddrStr(const u_char* addr)
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
return zeek::make_intrusive<zeek::StringVal>(buf);
|
||||
}
|
||||
|
||||
void ARPAnalyzer::BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...)
|
||||
{
|
||||
if ( ! bad_arp )
|
||||
return;
|
||||
|
||||
char msg[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
event_mgr.Enqueue(bad_arp,
|
||||
ToAddrVal(ar_spa(hdr)), ToEthAddrStr((const u_char*) ar_sha(hdr)),
|
||||
ToAddrVal(ar_tpa(hdr)), ToEthAddrStr((const u_char*) ar_tha(hdr)),
|
||||
zeek::make_intrusive<zeek::StringVal>(msg));
|
||||
}
|
||||
|
||||
void ARPAnalyzer::RequestReplyEvent(EventHandlerPtr e, const u_char *src, const u_char *dst,
|
||||
const char *spa, const char *sha, const char *tpa, const char *tha)
|
||||
{
|
||||
if ( ! e )
|
||||
return;
|
||||
|
||||
event_mgr.Enqueue(e, ToEthAddrStr(src), ToEthAddrStr(dst),
|
||||
ToAddrVal(spa), ToEthAddrStr((const u_char*) sha),
|
||||
ToAddrVal(tpa), ToEthAddrStr((const u_char*) tha));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
#include <packet_analysis/Analyzer.h>
|
||||
#include <packet_analysis/Component.h>
|
||||
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#ifndef arp_pkthdr
|
||||
#define arp_pkthdr arphdr
|
||||
#endif
|
||||
|
||||
namespace zeek::packet_analysis::ARP {
|
||||
|
||||
class ARPAnalyzer : public Analyzer {
|
||||
|
@ -18,6 +24,15 @@ public:
|
|||
{
|
||||
return std::make_shared<ARPAnalyzer>();
|
||||
}
|
||||
|
||||
private:
|
||||
zeek::AddrValPtr ToAddrVal(const void* addr);
|
||||
zeek::StringValPtr ToEthAddrStr(const u_char* addr);
|
||||
|
||||
void BadARPEvent(const struct arp_pkthdr* hdr, const char* fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
void RequestReplyEvent(EventHandlerPtr e, const u_char* src, const u_char* dst,
|
||||
const char* spa, const char* sha, const char* tpa, const char* tha);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(PacketAnalyzer ARP)
|
||||
zeek_plugin_begin(Zeek ARP)
|
||||
zeek_plugin_cc(ARP.cc Plugin.cc)
|
||||
zeek_plugin_bif(events.bif)
|
||||
zeek_plugin_end()
|
||||
|
|
63
src/packet_analysis/protocol/arp/events.bif
Normal file
63
src/packet_analysis/protocol/arp/events.bif
Normal file
|
@ -0,0 +1,63 @@
|
|||
## Generated for ARP requests.
|
||||
##
|
||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Address_Resolution_Protocol>`__
|
||||
## for more information about the ARP protocol.
|
||||
##
|
||||
## mac_src: The request's source MAC address.
|
||||
##
|
||||
## mac_dst: The request's destination MAC address.
|
||||
##
|
||||
## SPA: The sender protocol address.
|
||||
##
|
||||
## SHA: The sender hardware address.
|
||||
##
|
||||
## TPA: The target protocol address.
|
||||
##
|
||||
## THA: The target hardware address.
|
||||
##
|
||||
## .. zeek:see:: arp_reply bad_arp
|
||||
event arp_request%(mac_src: string, mac_dst: string, SPA: addr, SHA: string,
|
||||
TPA: addr, THA: string%);
|
||||
|
||||
## Generated for ARP replies.
|
||||
##
|
||||
## See `Wikipedia <http://en.wikipedia.org/wiki/Address_Resolution_Protocol>`__
|
||||
## for more information about the ARP protocol.
|
||||
##
|
||||
## mac_src: The reply's source MAC address.
|
||||
##
|
||||
## mac_dst: The reply's destination MAC address.
|
||||
##
|
||||
## SPA: The sender protocol address.
|
||||
##
|
||||
## SHA: The sender hardware address.
|
||||
##
|
||||
## TPA: The target protocol address.
|
||||
##
|
||||
## THA: The target hardware address.
|
||||
##
|
||||
## .. zeek:see:: arp_request bad_arp
|
||||
event arp_reply%(mac_src: string, mac_dst: string, SPA: addr, SHA: string,
|
||||
TPA: addr, THA: string%);
|
||||
|
||||
## Generated for ARP packets that Zeek cannot interpret. Examples are packets
|
||||
## with non-standard hardware address formats or hardware addresses that do not
|
||||
## match the originator of the packet.
|
||||
##
|
||||
## SPA: The sender protocol address.
|
||||
##
|
||||
## SHA: The sender hardware address.
|
||||
##
|
||||
## TPA: The target protocol address.
|
||||
##
|
||||
## THA: The target hardware address.
|
||||
##
|
||||
## explanation: A short description of why the ARP packet is considered "bad".
|
||||
##
|
||||
## .. zeek:see:: arp_reply arp_request
|
||||
##
|
||||
## .. todo:: Zeek's current default configuration does not activate the protocol
|
||||
## analyzer that generates this event; the corresponding script has not yet
|
||||
## been ported. To still enable this event, one needs to
|
||||
## register a port for it or add a DPD payload signature.
|
||||
event bad_arp%(SPA: addr, SHA: string, TPA: addr, THA: string, explanation: string%);
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(PacketAnalyzer IPv6)
|
||||
zeek_plugin_cc(IPv6.cc Plugin.cc)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(PacketAnalyzer LinuxSLL)
|
||||
zeek_plugin_cc(LinuxSLL.cc Plugin.cc)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
include(ZeekPlugin)
|
||||
|
||||
include_directories(BEFORE $ {CMAKE_CURRENT_SOURCE_DIR} $ {CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
zeek_plugin_begin(PacketAnalyzer Null)
|
||||
zeek_plugin_cc(Null.cc Plugin.cc)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue