• zeek学习(五)—— 会话建立


    zeek源码分析 - 会话建立

    IPBasedAnalyzer

    一个基于IP的包分析器重用的基类。这是默认的通过TCP, UDP和ICMP的分析器来减少大量的重复代码。

    class IPBasedAnalyzer : public Analyzer
    	{
    public:
    	~IPBasedAnalyzer() override;
        
        // 分析包,首先被调用
    	bool AnalyzePacket(size_t len, const uint8_t* data, Packet* packet) override;
    
         // 如果分析器确定实际上已经启动了一个新连接,而连接语句没有终止前一个连接,则返回true,即,新数据到达了前一个实例的分析器。
         // 是否重用,仅限于TCP
    	virtual bool IsReuse(double t, const u_char* pkt) { return false; }
    
        // 注册一个端口
    	bool RegisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
    
        // 取消注册端口
    	bool UnregisterAnalyzerForPort(const zeek::Tag& tag, uint32_t port);
    
    	void DumpPortDebug();
    	static void SetIgnoreChecksumsNets(TableValPtr t);
    	static TableValPtr GetIgnoreChecksumsNets();
    
    protected:
    	
    	IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask,
    	                bool report_unknown_protocols);
    
         // 将报头解析为ConnTuple对象
    	virtual bool BuildConnTuple(size_t len, const uint8_t* data, Packet* packet,
    	                            ConnTuple& tuple) = 0;
    
        //将连接插入后继续处理数据包会话管理器。这应该被所有的子类实现。
    	virtual void DeliverPacket(Connection* conn, double t, bool is_orig, int remaining, Packet* pkt)
    		{
    		}
    
        //在看到连接的第一个包时,检查是否需要分析它(例如,我们可能不想看部分连接)
        //如果是,我们是否应该互换发起者和响应器基于已知的端口等。
    	virtual bool WantConnection(uint16_t src_port, uint16_t dst_port, const u_char* data,
    	                            bool& flip_roles) const
    		{
    		flip_roles = false;
    		return true;
    		}
    
    	// 返回会话连接适配器
    	virtual SessionAdapter* MakeSessionAdapter(Connection* conn) = 0;
    
    	virtual analyzer::pia::PIA* MakePIA(Connection* conn) { return nullptr; }
    
    	/**
    	 * Verifies that there is enough data in the packet to process the header
    	 * length requested.
    	 *
    	 * @param min_hdr_len The minimum data in bytes that needs to exist.
    	 * @param remaining The remaining number of bytes in the packet reported by
    	 * previous analyzer.
    	 * @param packet The packet being processed. This will be used to pull out the
    	 * number of bytes the IP header says we have remaining.
    	 */
    	bool CheckHeaderTrunc(size_t min_hdr_len, size_t remaining, Packet* packet);
    
    	/**
    	 * Returns true if the port corresponds to an application for which there
    	 * is a Zeek analyzer (even if it might not be used by the present policy
    	 * script) or if it's generally a likely server port.
    	 *
    	 * @param port The port number to check, in host order.
    	 */
    	bool IsLikelyServerPort(uint32_t port) const;
    
    private:
    	// While this is storing session analyzer tags, we store it here since packet analyzers
    	// are persitent objects. We can't do this in the adapters because those get created
    	// and destroyed for each connection.
    	using tag_set = std::set<zeek::Tag>;
    	using analyzer_map_by_port = std::map<uint32_t, tag_set*>;
    	analyzer_map_by_port analyzers_by_port;
    
    	tag_set* LookupPort(uint32_t port, bool add_if_not_found);
    
    	/**
    	 * Creates a new Connection object from data gleaned from the current packet.
    	 *
    	 * @param id A connection ID generated from the packet data. This should have been
    	 * passed in from a child analyzer.
    	 * @param key A connection ID key generated from the ID.
    	 * @param pkt The packet associated with the new connection.
    	 */
    	zeek::Connection* NewConn(const ConnTuple* id, const detail::ConnKey& key, const Packet* pkt);
    
    	void BuildSessionAnalyzerTree(Connection* conn);
    
    	TransportProto transport;
    	uint32_t server_port_mask;
    	static TableValPtr ignore_checksums_nets_table;
    	};
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    AnalyzePacket

    此函数是传输层前的处理函数:

    1. 生成ConnTuple即key
    2. 查找key
    3. 找不到key,新建一个连接,并插入到管理器中
    4. 找到key,检测连接是否断开,断开重组并重新建立
    bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt)
    {
    	// 建立key
    	ConnTuple tuple;
    	if ( ! BuildConnTuple(len, data, pkt, tuple) )
    		return false;
    
    	const std::shared_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
    	detail::ConnKey key(tuple);
    
    	Connection* conn = session_mgr->FindConnection(key);
    
    	if ( ! conn )
    	{
    		// 连接不存在,建立连接
    		conn = NewConn(&tuple, key, pkt);
    		// 插入到管理器中即添加到map中
    		if ( conn )
    			session_mgr->Insert(conn, false);
    	}
    	else
    	{
    		// 判断
    		if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) )
    		{
    			conn->Event(connection_reused, nullptr);
    
    			session_mgr->Remove(conn);
    			conn = NewConn(&tuple, key, pkt);
    			if ( conn )
    				session_mgr->Insert(conn, false);
    		}
    		else
    		{
    			conn->CheckEncapsulation(pkt->encap);
    		}
    	}
    
    	if ( ! conn )
    		return false;
    
    	// If we successfuly made a connection for this packet that means it'll eventually
    	// get logged, which means we can mark this packet as having been processed.
    	pkt->processed = true;
    
    	bool is_orig = (tuple.src_addr == conn->OrigAddr()) && (tuple.src_port == conn->OrigPort());
    	pkt->is_orig = is_orig;
    	// IPV6的
    	conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel());
    
    	zeek::ValPtr pkt_hdr_val;
    	// IPV6的
    	if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 )
    	{
    		pkt_hdr_val = ip_hdr->ToPktHdrVal();
    		conn->EnqueueEvent(ipv6_ext_headers, nullptr, conn->GetVal(), pkt_hdr_val);
    	}
    	// 事件回调
    	if ( new_packet )
    		conn->EnqueueEvent(new_packet, nullptr, conn->GetVal(),
    		                   pkt_hdr_val ? std::move(pkt_hdr_val) : ip_hdr->ToPktHdrVal());
    
    	conn->SetRecordPackets(true);
    	conn->SetRecordContents(true);
    
    	const u_char* payload = pkt->ip_hdr->Payload();
    
    	run_state::current_timestamp = run_state::processing_start_time;
    	run_state::current_pkt = pkt;
    
    	// TODO: Does this actually mean anything?
    	if ( conn->GetSessionAdapter()->Skipping() )
    		return true;
    	// 分离到响应的子类处理
    	DeliverPacket(conn, run_state::processing_start_time, is_orig, len, pkt);
    
    	run_state::current_timestamp = 0;
    	run_state::current_pkt = nullptr;
    
    
    	// 重组包,不进行dump
    	if ( pkt->ip_hdr->Reassembled() )
    		pkt->dump_packet = false;
    	else if ( conn->RecordPackets() )
    	{
    		pkt->dump_packet = true;
    
    		// If we don't want the content, set the dump size to include just
    		// the header.
    		if ( ! conn->RecordContents() )
    			pkt->dump_size = payload - pkt->data;
    	}
    
    	return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    BuildConnTuple

    UDP

    bool UDPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, ConnTuple& tuple)
    {
        uint32_t min_hdr_len = sizeof(struct udphdr);
        if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) )
            return false;
        
        tuple.src_addr = packet->ip_hdr->SrcAddr();
        tuple.dst_addr = packet->ip_hdr->DstAddr();
        
        const struct udphdr* up = (const struct udphdr*)packet->ip_hdr->Payload();
        tuple.src_port = up->uh_sport;
        tuple.dst_port = up->uh_dport;
        tuple.is_one_way = false;
        tuple.proto = TRANSPORT_UDP;
        
        return true;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    TCP

    bool TCPAnalyzer::BuildConnTuple(size_t len, const uint8_t* data, Packet* packet, ConnTuple& tuple)
    {
        uint32_t min_hdr_len = sizeof(struct tcphdr);
        if ( ! CheckHeaderTrunc(min_hdr_len, len, packet) )
            return false;
        
        tuple.src_addr = packet->ip_hdr->SrcAddr();
        tuple.dst_addr = packet->ip_hdr->DstAddr();
        
        data = packet->ip_hdr->Payload();
        
        const struct tcphdr* tp = (const struct tcphdr*)data;
        tuple.src_port = tp->th_sport;
        tuple.dst_port = tp->th_dport;
        tuple.is_one_way = false;
        tuple.proto = TRANSPORT_TCP;
        
        return true;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    FindConnection

    using SessionMap = std::unordered_map<detail::Key, Session*, detail::KeyHash>;
    
    Connection* Manager::FindConnection(const zeek::detail::ConnKey& conn_key)
    {
    	detail::Key key(&conn_key, sizeof(conn_key), detail::Key::CONNECTION_KEY_TYPE, false);
    
    	auto it = session_map.find(key);
    	if ( it != session_map.end() )
    		return static_cast<Connection*>(it->second);
    
    	return nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    NewConn

    zeek::Connection* IPBasedAnalyzer::NewConn(const ConnTuple* id, const detail::ConnKey& key,
                                               const Packet* pkt)
    {
    
    	int src_h = ntohs(id->src_port);
    	int dst_h = ntohs(id->dst_port);
    	bool flip = false;
    	// 检查是否需要分析此连接,并且检查是否反转服务器/客户端角色
    	if ( ! WantConnection(src_h, dst_h, pkt->ip_hdr->Payload(), flip) )
    		return nullptr;
    
    	// 构造Connection对象
    	Connection* conn = new Connection(key, run_state::processing_start_time, id,
    	                                  pkt->ip_hdr->FlowLabel(), pkt);
    	// 设置传输层协议
    	conn->SetTransport(transport);
    
    	// 反转服务器/客户端角色
    	if ( flip )
    		conn->FlipRoles();
    	// 构建协议分析器
    	BuildSessionAnalyzerTree(conn);
    
    	if ( new_connection )
    		conn->Event(new_connection, nullptr);
    
    	return conn;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    BuildSessionAnalyzerTree

    void IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn)
    {
    	SessionAdapter* root = MakeSessionAdapter(conn);
    	analyzer::pia::PIA* pia = MakePIA(conn);
    
    	bool scheduled = analyzer_mgr->ApplyScheduledAnalyzers(conn, false, root);
    
    	// Hmm... Do we want *just* the expected analyzer, or all
    	// other potential analyzers as well?  For now we only take
    	// the scheduled ones.
    	if ( ! scheduled )
    	{ // Let's see if it's a port we know.
    		if ( ! analyzers_by_port.empty() && ! zeek::detail::dpd_ignore_ports )
    		{
    			int resp_port = ntohs(conn->RespPort());
    			std::set<zeek::Tag>* ports = LookupPort(resp_port, false);
    
    			if ( ports )
    			{
    				for ( const auto& port : *ports )
    				{
    					analyzer::Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(port, conn);
    
    					if ( ! analyzer )
    						continue;
    
    					root->AddChildAnalyzer(analyzer, false);
    					DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
    					                  analyzer_mgr->GetComponentName(port).c_str(), resp_port);
    				}
    			}
    		}
    	}
    
    	root->AddExtraAnalyzers(conn);
    
    	if ( pia )
    		root->AddChildAnalyzer(pia->AsAnalyzer());
    
    	conn->SetSessionAdapter(root, pia);
    	root->Init();
    	root->InitChildren();
    
    	PLUGIN_HOOK_VOID(HOOK_SETUP_ANALYZER_TREE, HookSetupAnalyzerTree(conn));
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    MakeSessionAdapter

    SessionAdapter* TCPAnalyzer::MakeSessionAdapter(Connection* conn)
    {
    	auto* root = new TCPSessionAdapter(conn);
    	root->SetParent(this);
    
    	conn->EnableStatusUpdateTimer();
    	conn->SetInactivityTimeout(zeek::detail::udp_inactivity_timeout);
    
    	return root;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ApplyScheduleAnalyzers

    bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init,
                                          packet_analysis::IP::SessionAdapter* parent)
    {
    	if ( ! parent )
    		parent = conn->GetSessionAdapter();
    
    	if ( ! parent )
    		return false;
    
    	tag_set expected = GetScheduled(conn);
    
    	for ( tag_set::iterator it = expected.begin(); it != expected.end(); ++it )
    	{
    		Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*it, conn);
    
    		if ( ! analyzer )
    			continue;
    
    		parent->AddChildAnalyzer(analyzer, init);
    
    		if ( scheduled_analyzer_applied )
    			conn->EnqueueEvent(scheduled_analyzer_applied, nullptr, conn->GetVal(), it->AsVal());
    
    		DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
    		                  analyzer_mgr->GetComponentName(*it).c_str());
    		}
    
    	return expected.size();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Insert

    void Manager::Insert(Session* s, bool remove_existing)
    {
    	Session* old = nullptr;
    	detail::Key key = s->SessionKey(true);
    
    	if ( remove_existing )
    	{
    		auto it = session_map.find(key);
    		if ( it != session_map.end() )
    			old = it->second;
    
    		session_map.erase(key);
    	}
    
    	InsertSession(std::move(key), s);
    
    	if ( old && old != s )
    	{
    		// Some clean-ups similar to those in Remove() (but invisible
    		// to the script layer).
    		old->CancelTimers();
    		old->SetInSessionTable(false);
    		Unref(old);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Connection

    class Session : public Obj
    {
    public:
    
    Session(double t, EventHandlerPtr timeout_event, EventHandlerPtr status_update_event = nullptr,
    double status_update_interval = 0);
    
    virtual ~Session() { }
    
    /**
    * 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.
    */
    virtual void Done() = 0;
    
    /**
    * Returns a key for the session. This is used as the key for storing
    * the session in SessionManager.
    *
    * @param copy Flag to indicate that the key returned must have a copy of the
    * key data instead of just a pointer to it.
    */
    virtual detail::Key SessionKey(bool copy) const = 0;
    
    /**
    * Set whether this session is in the session table.
    */
    void SetInSessionTable(bool in_table) { in_session_table = in_table; }
    
    /**
    * Return whether this session is in the session table.
    */
    bool IsInSessionTable() const { return in_session_table; }
    
    double StartTime() const { return start_time; }
    void SetStartTime(double t) { start_time = t; }
    double LastTime() const { return last_time; }
    void SetLastTime(double t) { last_time = t; }
    
    // True if we should record subsequent packets (either headers or
    // in their entirety, depending on record_contents).  We still
    // record subsequent SYN/FIN/RST, regardless of how this is set.
    bool RecordPackets() const { return record_packets; }
    void SetRecordPackets(bool do_record) { record_packets = do_record ? 1 : 0; }
    
    // True if we should record full packets for this session,
    // false if we should just record headers.
    bool RecordContents() const { return record_contents; }
    void SetRecordContents(bool do_record) { record_contents = do_record ? 1 : 0; }
    
    // Set whether to record *current* packet header/full.
    void SetRecordCurrentPacket(bool do_record) { record_current_packet = do_record ? 1 : 0; }
    void SetRecordCurrentContent(bool do_record) { record_current_content = do_record ? 1 : 0; }
    
    /**
    * Returns the associated "session" record.
    */
    virtual const RecordValPtr& GetVal() = 0;
    
    [[deprecated("Remove in v5.1. Use GetVal().")]] const RecordValPtr& ConnVal()
    {
    return GetVal();
    }
    
    /**
    * Return the memory allocation required by the session record. This requires at
    * least one call to Get() first in order to setup the record object.
    */
    [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See "
    "GHI-572.")]] virtual unsigned int
    MemoryAllocationVal() const = 0;
    
    [[deprecated("Remove in v5.1. Use MemoryAllocationVal().")]] unsigned int
    MemoryAllocationConnVal() const
    {
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    return MemoryAllocationVal();
    #pragma GCC diagnostic pop
    }
    
    /**
    * A lower-bound calculation of how much memory a session object is using.
    */
    [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See "
    "GHI-572.")]] virtual unsigned int
    MemoryAllocation() const;
    
    /**
    * Generates session removal event(s). Must be overridden by child classes to
    * provide specific removal events.
    */
    virtual void RemovalEvent() = 0;
    
    /**
    * Generate an event for this session.
    *
    * @param f The handler for the event to be generated. If the handler doesn't
    * exist, this method doesn't generate anything.
    * @param analyzer
    * @param name If given, this will be passed as the first argument to the
    * handler, followed by the session value. If null, then the event's first
    * argument is the session value.
    */
    void Event(EventHandlerPtr f, analyzer::Analyzer* analyzer = nullptr,
    const char* name = nullptr);
    
    /**
    * Enqueues an event associated with this session and given analyzer.
    */
    void EnqueueEvent(EventHandlerPtr f, analyzer::Analyzer* analyzer, Args args);
    
    /**
    * A version of EnqueueEvent() taking a variable number of arguments.
    */
    template <class... Args>
    std::enable_if_t<std::is_convertible_v<std::tuple_element_t<0, std::tuple<Args...>>, ValPtr>>
    EnqueueEvent(EventHandlerPtr h, analyzer::Analyzer* analyzer, Args&&... args)
    {
    return EnqueueEvent(h, analyzer, zeek::Args{std::forward<Args>(args)...});
    }
    
    virtual void Describe(ODesc* d) const override;
    
    /**
    * Sets the session to expire after a given amount of time.
    *
    * @param lifetime The amount of time in seconds from the current network time.
    */
    void SetLifetime(double lifetime);
    
    /**
    * Sets the inactivity timeout for this session.
    *
    * @param timeout The number of seconds of inactivity allowed for this session
    * before it times out.
    */
    void SetInactivityTimeout(double timeout);
    
    /**
    * Returns the inactivity timeout for the session.
    */
    double InactivityTimeout() const { return inactivity_timeout; }
    
    /**
    * Activates the timer for the status update event.
    */
    void EnableStatusUpdateTimer();
    
    /**
    * Cancels all timers associated with this session.
    */
    void CancelTimers();
    
    /**
    * Called when the lifetime of the session expires. Fires a timeout event and
    * removes the session from the manager.
    * TODO: This function has a terrible name considering there's an AddTimer() and
    * a RemoveTimer() method in this class as well.
    *
    * @param t This argument is ignored.
    */
    void DeleteTimer(double t);
    
    /**
    * Returns a string representation of the transport protocol referenced by the
    * session. This is used by SessionManager for statistics.
    */
    virtual std::string TransportIdentifier() const = 0;
    
    AnalyzerConfirmationState AnalyzerState(const zeek::Tag& tag) const;
    void SetAnalyzerState(const zeek::Tag& tag, AnalyzerConfirmationState);
    
    protected:
    friend class detail::Timer;
    
    /**
    * Add a given timer to expire at a specific time.
    *
    * @param timer A pointer to a method that will be called when the timer expires.
    * @param t The time when the timer expires. This is an absolute time, not a time
    * relative to the current network time.
    * @param do_expire If set to true, the timer is also evaluated when Zeek
    * terminates.
    * @param type The type of timer being added.
    */
    void AddTimer(timer_func timer, double t, bool do_expire, zeek::detail::TimerType type);
    
    /**
    * Remove a specific timer from firing.
    */
    void RemoveTimer(zeek::detail::Timer* t);
    
    /**
    * The handler method for inactivity timers.
    */
    void InactivityTimer(double t);
    
    /**
    * The handler method for status update timers.
    */
    void StatusUpdateTimer(double t);
    
    // TODO: is this method used by anyone?
    void RemoveConnectionTimer(double t);
    
    double start_time, last_time;
    TimerPList timers;
    double inactivity_timeout;
    
    EventHandlerPtr session_timeout_event;
    EventHandlerPtr session_status_update_event;
    double session_status_update_interval;
    
    unsigned int installed_status_timer : 1;
    unsigned int timers_canceled : 1;
    unsigned int is_active : 1;
    unsigned int record_packets : 1, record_contents : 1;
    unsigned int record_current_packet : 1, record_current_content : 1;
    bool in_session_table;
    
    std::map<zeek::Tag, AnalyzerConfirmationState> analyzer_confirmations;
    };
    
    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";
    }
    
    // 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;
    
    /**
    * Append additional entries to the history field in the connection record.
    */
    void AppendAddl(const char* str);
    
    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.
    
    // Just a lower bound.
    [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See "
    "GHI-572.")]] unsigned int
    MemoryAllocation() const override;
    [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See "
    "GHI-572.")]] unsigned int
    MemoryAllocationVal() const override;
    
    static uint64_t TotalConnections() { return total_connections; }
    static uint64_t CurrentConnections() { return current_connections; }
    
    // Returns true if the history was already seen, false otherwise.
    bool CheckHistory(uint32_t mask, char code)
    {
    if ( (hist_seen & mask) == 0 )
    {
    hist_seen |= mask;
    AddHistory(code);
    return false;
    }
    else
    return true;
    }
    
    // Increments the passed counter and adds it as a history
    // code if it has crossed the next scaling threshold.  Scaling
    // is done in terms of powers of the third argument.
    // Returns true if the threshold was crossed, false otherwise.
    bool ScaledHistoryEntry(char code, uint32_t& counter, uint32_t& scaling_threshold,
    uint32_t scaling_base = 10);
    
    void HistoryThresholdEvent(EventHandlerPtr e, bool is_orig, uint32_t threshold);
    
    void AddHistory(char code) { history += code; }
    
    // 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);
    
    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
    
    detail::ConnKey key;
    
    unsigned int weird : 1;
    unsigned int finished : 1;
    unsigned int saw_first_orig_packet : 1, saw_first_resp_packet : 1;
    
    uint32_t hist_seen;
    std::string history;
    
    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;
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431

  • 相关阅读:
    SquirrelMail实现Web方式收发邮件_xionglling的博客-CSDN博客
    1800亿参数,支持中文,3.5万亿训练数据!开源类ChatGPT模型
    【HBU】数据结构第一次月测题(线性结构)
    AI新工具 百分50%算力确达到了GPT-4水平;将音乐轨道中的人声、鼓声、贝斯等音源分离出来等
    【番杰的小技巧笔记】如何通过嘉立创免费3D打印
    云服务器的安全设置常识
    电脑重装系统后如何给系统磁盘扩容空间
    Burpsuite抓HTTPS证书导入问题
    CEF | CEF浏览器客户端能扩展:实现与JS交互
    分销小程序开发|分销小程序怎么设计动态分销?
  • 原文地址:https://blog.csdn.net/hzb869168467/article/details/126338220