既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
- 生成ConnTuple即key
- 查找key
- 找不到key,新建一个连接,并插入到管理器中
- 找到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>(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);
![img](https://img-blog.csdnimg.cn/img_convert/4fc44ba20758c198b2823f563361e71d.png)
![img](https://img-blog.csdnimg.cn/img_convert/8da1335e8f53856faa59dcbcffb5189b.png)
![img](https://img-blog.csdnimg.cn/img_convert/70e3ddd7bc611863bc8cb09c80d0332d.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
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);
[外链图片转存中...(img-4cYi40y8-1715404582455)]
[外链图片转存中...(img-Wne4Hh98-1715404582456)]
[外链图片转存中...(img-Kxp3mUk2-1715404582456)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**