mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
239 lines
7.6 KiB
C++
239 lines
7.6 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#pragma once
|
|
|
|
#include <sys/types.h>
|
|
#include <string>
|
|
|
|
#include "zeek/IPAddr.h"
|
|
#include "zeek/IntrusivePtr.h"
|
|
#include "zeek/Rule.h"
|
|
#include "zeek/Tag.h"
|
|
#include "zeek/Timer.h"
|
|
#include "zeek/UID.h"
|
|
#include "zeek/WeirdState.h"
|
|
#include "zeek/ZeekArgs.h"
|
|
#include "zeek/analyzer/Analyzer.h"
|
|
#include "zeek/iosource/Packet.h"
|
|
#include "zeek/session/Session.h"
|
|
|
|
namespace zeek {
|
|
|
|
class Connection;
|
|
class EncapsulationStack;
|
|
class Val;
|
|
class RecordVal;
|
|
|
|
using ValPtr = IntrusivePtr<Val>;
|
|
using RecordValPtr = IntrusivePtr<RecordVal>;
|
|
|
|
namespace session {
|
|
class Manager;
|
|
}
|
|
namespace detail {
|
|
|
|
class Specific_RE_Matcher;
|
|
class RuleEndpointState;
|
|
class RuleHdrTest;
|
|
|
|
} // namespace detail
|
|
|
|
namespace analyzer {
|
|
class Analyzer;
|
|
}
|
|
namespace packet_analysis::IP {
|
|
class SessionAdapter;
|
|
}
|
|
|
|
enum ConnEventToFlag {
|
|
NUL_IN_LINE,
|
|
SINGULAR_CR,
|
|
SINGULAR_LF,
|
|
NUM_EVENTS_TO_FLAG,
|
|
};
|
|
|
|
struct ConnTuple {
|
|
IPAddr src_addr;
|
|
IPAddr dst_addr;
|
|
uint32_t src_port = 0;
|
|
uint32_t dst_port = 0;
|
|
uint16_t proto = UNKNOWN_IP_PROTO;
|
|
bool is_one_way = false; // if true, don't canonicalize order
|
|
};
|
|
|
|
static inline int addr_port_canon_lt(const IPAddr& addr1, uint32_t p1, const IPAddr& addr2, uint32_t p2) {
|
|
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
|
|
}
|
|
|
|
class Connection final : public session::Session {
|
|
public:
|
|
Connection(const detail::ConnKey& k, double t, const ConnTuple* id, uint32_t flow, const Packet* pkt);
|
|
~Connection() override;
|
|
|
|
/**
|
|
* Invoked when an encapsulation is discovered. It records the encapsulation
|
|
* with the connection and raises a "tunnel_changed" event if it's different
|
|
* from the previous encapsulation or if it's the first one encountered.
|
|
*
|
|
* @param encap The new encapsulation. Can be set to null to indicated no
|
|
* encapsulation or clear an old one.
|
|
*/
|
|
void CheckEncapsulation(const std::shared_ptr<EncapsulationStack>& encap);
|
|
|
|
/**
|
|
* Invoked when the session is about to be removed. Use Ref(this)
|
|
* inside Done to keep the session object around, though it'll
|
|
* no longer be accessible from the SessionManager.
|
|
*/
|
|
void Done() override;
|
|
|
|
// Process the connection's next packet. "data" points just
|
|
// beyond the IP header. It's updated to point just beyond
|
|
// the transport header (or whatever should be saved, if we
|
|
// decide not to save the full packet contents).
|
|
//
|
|
// If record_packet is true, the packet should be recorded.
|
|
// If record_content is true, then its entire contents should
|
|
// be recorded, otherwise just up through the transport header.
|
|
// Both are assumed set to true when called.
|
|
void NextPacket(double t, bool is_orig, const IP_Hdr* ip, int len, int caplen, const u_char*& data,
|
|
int& record_packet, int& record_content,
|
|
// arguments for reproducing packets
|
|
const Packet* pkt);
|
|
|
|
// Keys are only considered valid for a connection when a
|
|
// connection is in the session map. If it is removed, the key
|
|
// should be marked invalid.
|
|
const detail::ConnKey& Key() const { return key; }
|
|
session::detail::Key SessionKey(bool copy) const override {
|
|
return session::detail::Key{&key, sizeof(key), session::detail::Key::CONNECTION_KEY_TYPE, copy};
|
|
}
|
|
|
|
const IPAddr& OrigAddr() const { return orig_addr; }
|
|
const IPAddr& RespAddr() const { return resp_addr; }
|
|
|
|
uint32_t OrigPort() const { return orig_port; }
|
|
uint32_t RespPort() const { return resp_port; }
|
|
|
|
void FlipRoles();
|
|
|
|
analyzer::Analyzer* FindAnalyzer(analyzer::ID id);
|
|
analyzer::Analyzer* FindAnalyzer(const zeek::Tag& tag); // find first in tree.
|
|
analyzer::Analyzer* FindAnalyzer(const char* name); // find first in tree.
|
|
|
|
TransportProto ConnTransport() const { return proto; }
|
|
std::string TransportIdentifier() const override {
|
|
if ( proto == TRANSPORT_TCP )
|
|
return "tcp";
|
|
else if ( proto == TRANSPORT_UDP )
|
|
return "udp";
|
|
else if ( proto == TRANSPORT_ICMP )
|
|
return "icmp";
|
|
else
|
|
return "unknown";
|
|
}
|
|
|
|
uint8_t KeyProto() const { return key.transport; }
|
|
|
|
// Returns true if the packet reflects a reuse of this
|
|
// connection (i.e., not a continuation but the beginning of
|
|
// a new connection).
|
|
bool IsReuse(double t, const u_char* pkt);
|
|
|
|
/**
|
|
* Returns the associated "connection" record.
|
|
*/
|
|
const RecordValPtr& GetVal() override;
|
|
|
|
void Match(detail::Rule::PatternType type, const u_char* data, int len, bool is_orig, bool bol, bool eol,
|
|
bool clear_state);
|
|
|
|
/**
|
|
* Generates connection removal event(s).
|
|
*/
|
|
void RemovalEvent() override;
|
|
|
|
void Weird(const char* name, const char* addl = "", const char* source = "");
|
|
bool DidWeird() const { return weird != 0; }
|
|
|
|
inline bool FlagEvent(ConnEventToFlag e) {
|
|
if ( e >= 0 && e < NUM_EVENTS_TO_FLAG ) {
|
|
if ( suppress_event & (1 << e) )
|
|
return false;
|
|
suppress_event |= 1 << e;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Describe(ODesc* d) const override;
|
|
void IDString(ODesc* d) const;
|
|
|
|
// Statistics.
|
|
|
|
static uint64_t TotalConnections() { return total_connections; }
|
|
static uint64_t CurrentConnections() { return current_connections; }
|
|
|
|
// Sets the root of the analyzer tree as well as the primary PIA.
|
|
void SetSessionAdapter(packet_analysis::IP::SessionAdapter* aa, analyzer::pia::PIA* pia);
|
|
packet_analysis::IP::SessionAdapter* GetSessionAdapter() { return adapter; }
|
|
analyzer::pia::PIA* GetPrimaryPIA() { return primary_PIA; }
|
|
|
|
// Sets the transport protocol in use.
|
|
void SetTransport(TransportProto arg_proto) { proto = arg_proto; }
|
|
|
|
void SetUID(const UID& arg_uid) { uid = arg_uid; }
|
|
|
|
UID GetUID() const { return uid; }
|
|
|
|
std::shared_ptr<EncapsulationStack> GetEncapsulation() const { return encapsulation; }
|
|
|
|
void CheckFlowLabel(bool is_orig, uint32_t flow_label);
|
|
|
|
uint32_t GetOrigFlowLabel() { return orig_flow_label; }
|
|
uint32_t GetRespFlowLabel() { return resp_flow_label; }
|
|
|
|
bool PermitWeird(const char* name, uint64_t threshold, uint64_t rate, double duration);
|
|
|
|
// Returns true once Done() is called.
|
|
bool IsFinished() { return finished; }
|
|
|
|
private:
|
|
friend class session::detail::Timer;
|
|
|
|
IPAddr orig_addr;
|
|
IPAddr resp_addr;
|
|
uint32_t orig_port, resp_port; // in network order
|
|
TransportProto proto;
|
|
uint32_t orig_flow_label, resp_flow_label; // most recent IPv6 flow labels
|
|
uint32_t vlan, inner_vlan; // VLAN this connection traverses, if available
|
|
u_char orig_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer originator address, if available
|
|
u_char resp_l2_addr[Packet::L2_ADDR_LEN]; // Link-layer responder address, if available
|
|
int suppress_event; // suppress certain events to once per conn.
|
|
RecordValPtr conn_val;
|
|
std::shared_ptr<EncapsulationStack> encapsulation; // tunnels
|
|
uint8_t tunnel_changes = 0;
|
|
|
|
detail::ConnKey key;
|
|
|
|
unsigned int weird : 1;
|
|
unsigned int finished : 1;
|
|
unsigned int saw_first_orig_packet : 1, saw_first_resp_packet : 1;
|
|
|
|
packet_analysis::IP::SessionAdapter* adapter;
|
|
analyzer::pia::PIA* primary_PIA;
|
|
|
|
UID uid; // Globally unique connection ID.
|
|
detail::WeirdStateMap weird_state;
|
|
|
|
// Count number of connections.
|
|
static uint64_t total_connections;
|
|
static uint64_t current_connections;
|
|
};
|
|
|
|
// The following is used by script optimization.
|
|
namespace detail {
|
|
extern RecordValPtr build_dummy_conn_record();
|
|
}
|
|
|
|
} // namespace zeek
|