Go最新zeek学习(五)—— 会话建立_zeek教程(2),附超全教程文档

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取


### 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;

}


### 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;
}

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;
}

### 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;

}


### 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;

}


#### 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));

}


##### 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;

}


##### 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();
}

### 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);
}

}


## 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)…});
}

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.

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

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.

[外链图片转存中…(img-QHiAR9Vq-1715888630736)]
[外链图片转存中…(img-Y5KpHBES-1715888630736)]
[外链图片转存中…(img-7Y9XtbFq-1715888630736)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值