zeek/src/analyzer/protocol/tcp/TCP.h
Jon Siwek a1c5eddb95 GH-532: improve disable_analyzer BIF
- Add an extra "prevent" parameter (default value of false), which
  helps prevent the same analyzer type from being attached in the
  future.  It's useful in situations where you want to disable early
  on, but a DPD signature may still trigger later and re-attach
  the same analyzer.  E.g. when not using this flag, but calling
  disable_analyzer() inside an http_request event, will remove the
  HTTP analyzer that was attached due to well-known-port, but a later
  DPD signature match from upon seeing the HTTP reply will end up
  attaching another HTTP analyzer.  More surprising is that upon
  re-attaching that analyzer, you'll get the same http_request as
  before since the DPD buffer will get replayed into the new analyzer.

- Fixes disable_analyzer() to work when called even earlier, like
  within the protocol_confirmation event.  At that time, the
  Analyzer tree may have not properly added the new analyzer into
  Analyzer::children yet, but rather the temporary waiting list,
  Analyzer::new_children.  Analyzer::RemoveChildAnalyzer previously
  did not inspect the later list.

- Fixes disable_analyzer() when called on an analyzer added to the
  tree via TCP_Analyzer::AddChildPacketAnalyzer.  TCP_Analyzer
  keeps track of such children in its own list,
  TCP_Analyzer::packet_children, which the previous
  Analyzer::RemoveChildAnalyzer implementation didn't inspect.
2019-08-09 20:03:26 -07:00

325 lines
10 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_TCP_TCP_H
#define ANALYZER_PROTOCOL_TCP_TCP_H
#include "analyzer/Analyzer.h"
#include "PacketDumper.h"
#include "IPAddr.h"
#include "TCP_Endpoint.h"
#include "TCP_Flags.h"
#include "Conn.h"
// We define two classes here:
// - TCP_Analyzer is the analyzer for the TCP protocol itself.
// - TCP_ApplicationAnalyzer is an abstract base class for analyzers for a
// protocol running on top of TCP.
//
namespace analyzer { namespace pia { class PIA_TCP; } };
namespace analyzer { namespace tcp {
class TCP_Endpoint;
class TCP_ApplicationAnalyzer;
class TCP_Reassembler;
class TCP_Analyzer : public analyzer::TransportLayerAnalyzer {
public:
explicit TCP_Analyzer(Connection* conn);
~TCP_Analyzer() override;
void EnableReassembly();
// Add a child analyzer that will always get the packets,
// independently of whether we do any reassembly.
void AddChildPacketAnalyzer(analyzer::Analyzer* a);
Analyzer* FindChild(ID id) override;
Analyzer* FindChild(Tag tag) override;
bool RemoveChildAnalyzer(ID id) override;
// True if the connection has closed in some sense, false otherwise.
int IsClosed() const { return orig->did_close || resp->did_close; }
int BothClosed() const { return orig->did_close && resp->did_close; }
int IsPartial() const { return is_partial; }
bool HadGap(bool orig) const;
TCP_Endpoint* Orig() const { return orig; }
TCP_Endpoint* Resp() const { return resp; }
int OrigState() const { return orig->state; }
int RespState() const { return resp->state; }
int OrigPrevState() const { return orig->prev_state; }
int RespPrevState() const { return resp->prev_state; }
uint32 OrigSeq() const { return orig->LastSeq(); }
uint32 RespSeq() const { return resp->LastSeq(); }
// True if either endpoint still has pending data. closing_endp
// is an endpoint that has indicated it is closing (i.e., for
// which we have seen a FIN) - for it, data is pending unless
// everything's been delivered up to the FIN. For its peer,
// the test is whether it has any outstanding, un-acked data.
int DataPending(TCP_Endpoint* closing_endp);
void SetContentsFile(unsigned int direction, BroFile* f) override;
BroFile* GetContentsFile(unsigned int direction) const override;
// Callback to process a TCP option.
typedef int (*proc_tcp_option_t)(unsigned int opt, unsigned int optlen,
const u_char* option, TCP_Analyzer* analyzer,
bool is_orig, void* cookie);
// From Analyzer.h
void UpdateConnVal(RecordVal *conn_val) override;
// Needs to be static because it's passed as a pointer-to-function
// rather than pointer-to-member-function.
static int ParseTCPOptions(const struct tcphdr* tcp,
proc_tcp_option_t proc, TCP_Analyzer* analyzer,
bool is_orig, void* cookie);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new TCP_Analyzer(conn); }
protected:
friend class TCP_ApplicationAnalyzer;
friend class TCP_Reassembler;
friend class analyzer::pia::PIA_TCP;
// Analyzer interface.
void Init() override;
void Done() override;
void DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen) override;
void DeliverStream(int len, const u_char* data, bool orig) override;
void Undelivered(uint64 seq, int len, bool orig) override;
void FlipRoles() override;
bool IsReuse(double t, const u_char* pkt) override;
// Returns the TCP header pointed to by data (which we assume is
// aligned), updating data, len & caplen. Returns nil if the header
// isn't fully present.
const struct tcphdr* ExtractTCP_Header(const u_char*& data, int& len,
int& caplen);
// Returns true if the checksum is valid, false if not (and in which
// case also updates the status history of the endpoint).
bool ValidateChecksum(const struct tcphdr* tp, TCP_Endpoint* endpoint,
int len, int caplen);
void SetPartialStatus(TCP_Flags flags, bool is_orig);
// Update the state machine of the TCPs based on the activity. This
// includes our pseudo-states such as TCP_ENDPOINT_PARTIAL.
//
// On return, do_close is true if we should consider the connection
// as closed, and gen_event if we shouuld generate an event about
// this fact.
void UpdateStateMachine(double t,
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
uint32 base_seq, uint32 ack_seq,
int len, int32 delta_last, int is_orig, TCP_Flags flags,
int& do_close, int& gen_event);
void UpdateInactiveState(double t,
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
uint32 base_seq, uint32 ack_seq,
int len, int is_orig, TCP_Flags flags,
int& do_close, int& gen_event);
void UpdateSYN_SentState(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
int len, int is_orig, TCP_Flags flags,
int& do_close, int& gen_event);
void UpdateEstablishedState(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
TCP_Flags flags, int& do_close, int& gen_event);
void UpdateClosedState(double t, TCP_Endpoint* endpoint,
int32 delta_last, TCP_Flags flags,
int& do_close);
void UpdateResetState(int len, TCP_Flags flags);
void GeneratePacketEvent(uint64 rel_seq, uint64 rel_ack,
const u_char* data, int len, int caplen,
int is_orig, TCP_Flags flags);
int DeliverData(double t, const u_char* data, int len, int caplen,
const IP_Hdr* ip, const struct tcphdr* tp,
TCP_Endpoint* endpoint, uint64 rel_data_seq,
int is_orig, TCP_Flags flags);
void CheckRecording(int need_contents, TCP_Flags flags);
void CheckPIA_FirstPacket(int is_orig, const IP_Hdr* ip);
friend class ConnectionTimer;
void AttemptTimer(double t);
void PartialCloseTimer(double t);
void ExpireTimer(double t);
void ResetTimer(double t);
void DeleteTimer(double t);
void ConnDeleteTimer(double t);
void EndpointEOF(TCP_Reassembler* endp);
void ConnectionClosed(TCP_Endpoint* endpoint,
TCP_Endpoint* peer, int gen_event);
void ConnectionFinished(int half_finished);
void ConnectionReset();
void PacketWithRST();
void SetReassembler(tcp::TCP_Reassembler* rorig, tcp::TCP_Reassembler* rresp);
// Needs to be static because it's passed as a pointer-to-function
// rather than pointer-to-member-function.
static int TCPOptionEvent(unsigned int opt, unsigned int optlen,
const u_char* option, TCP_Analyzer* analyzer,
bool is_orig, void* cookie);
// A couple utility functions that may also be useful to derived analyzers.
static uint64 get_relative_seq(const TCP_Endpoint* endpoint,
uint32 cur_base, uint32 last,
uint32 wraps, bool* underflow = 0);
static int get_segment_len(int payload_len, TCP_Flags flags);
private:
TCP_Endpoint* orig;
TCP_Endpoint* resp;
typedef list<analyzer::Analyzer*> analyzer_list;
analyzer_list packet_children;
unsigned int first_packet_seen: 2;
unsigned int reassembling: 1;
unsigned int is_partial: 1;
unsigned int is_active: 1;
unsigned int finished: 1;
// Whether we're waiting on final data delivery before closing
// this connection.
unsigned int close_deferred: 1;
// Whether to generate an event when we finally do close it.
unsigned int deferred_gen_event: 1;
// Whether we have seen the first ACK from the originator.
unsigned int seen_first_ACK: 1;
};
class TCP_ApplicationAnalyzer : public analyzer::Analyzer {
public:
TCP_ApplicationAnalyzer(const char* name, Connection* conn)
: Analyzer(name, conn)
{ tcp = 0; }
explicit TCP_ApplicationAnalyzer(Connection* conn)
: Analyzer(conn)
{ tcp = 0; }
~TCP_ApplicationAnalyzer() override { }
// This may be nil if we are not directly associated with a TCP
// analyzer (e.g., we're part of a tunnel decapsulation pipeline).
TCP_Analyzer* TCP()
{
return tcp ?
tcp :
static_cast<TCP_Analyzer*>(Conn()->FindAnalyzer("TCP"));
}
void SetTCP(TCP_Analyzer* arg_tcp) { tcp = arg_tcp; }
// The given endpoint's data delivery is complete.
virtual void EndpointEOF(bool is_orig);
// Called whenever an end enters TCP_ENDPOINT_CLOSED or
// TCP_ENDPOINT_RESET. If gen_event is true and the connection
// is now fully closed, a connection_finished event will be
// generated; otherwise not.
virtual void ConnectionClosed(analyzer::tcp::TCP_Endpoint* endpoint,
analyzer::tcp::TCP_Endpoint* peer, int gen_event);
virtual void ConnectionFinished(int half_finished);
virtual void ConnectionReset();
// Called whenever a RST packet is seen - sometimes the invocation
// of ConnectionReset is delayed.
virtual void PacketWithRST();
void DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen) override;
void Init() override;
// This suppresses violations if the TCP connection wasn't
// fully established.
void ProtocolViolation(const char* reason,
const char* data = 0, int len = 0) override;
// "name" and "val" both now belong to this object, which needs to
// delete them when done with them.
virtual void SetEnv(bool orig, char* name, char* val);
private:
TCP_Analyzer* tcp;
};
class TCP_SupportAnalyzer : public analyzer::SupportAnalyzer {
public:
TCP_SupportAnalyzer(const char* name, Connection* conn, bool arg_orig)
: analyzer::SupportAnalyzer(name, conn, arg_orig) { }
~TCP_SupportAnalyzer() override {}
// These are passed on from TCP_Analyzer.
virtual void EndpointEOF(bool is_orig) { }
virtual void ConnectionClosed(TCP_Endpoint* endpoint,
TCP_Endpoint* peer, int gen_event) { }
virtual void ConnectionFinished(int half_finished) { }
virtual void ConnectionReset() { }
virtual void PacketWithRST() { }
};
class TCPStats_Endpoint {
public:
explicit TCPStats_Endpoint(TCP_Endpoint* endp);
int DataSent(double t, uint64 seq, int len, int caplen, const u_char* data,
const IP_Hdr* ip, const struct tcphdr* tp);
RecordVal* BuildStats();
protected:
TCP_Endpoint* endp;
int num_pkts;
int num_rxmit;
int num_rxmit_bytes;
int num_in_order;
int num_OO;
int num_repl;
uint64 max_top_seq;
int last_id;
int endian_type;
};
class TCPStats_Analyzer : public tcp::TCP_ApplicationAnalyzer {
public:
explicit TCPStats_Analyzer(Connection* c);
~TCPStats_Analyzer() override;
void Init() override;
void Done() override;
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new TCPStats_Analyzer(conn); }
protected:
void DeliverPacket(int len, const u_char* data, bool is_orig,
uint64 seq, const IP_Hdr* ip, int caplen) override;
TCPStats_Endpoint* orig_stats;
TCPStats_Endpoint* resp_stats;
};
} } // namespace analyzer::*
#endif