既有适合小白学习的零基础资料,也有适合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.
既有适合小白学习的零基础资料,也有适合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语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新