最新zeek学习(三)——包获取_zeek pktdumper(2),2024年最新熬夜整理2024最新Golang高级笔试题

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

if (!component)
    reporter->FatalError("type of packet dumper '%s' not recognized", prefix.c\_str());

// Instantiate packet dumper.
//调用构造
PktDumper\* pd = (\*component->Factory())(npath, append);
assert(pd);

if (!pd->IsOpen() && pd->IsError())
    // Set an error message if it didn't open successfully.
    pd->Error("could not open");

DBG\_LOG(DBG_PKTIO, "Created packer dumper of type %s for %s", component->Name().c\_str(), npath.c\_str());

pd->Init();
pkt_dumpers.push\_back(pd);

return pd;

}


3. 构造



iosource::PktDumper* PcapDumper::Instantiate(const std::string& path, bool append)
{
return new PcapDumper(path, append);
}



#### Init


1. Init



void PktDumper::Init()
{
Open();
}


2. Open



void PcapDumper::Open()
{
int linktype = -1;

pd = pcap\_open\_dead(DLT_EN10MB, BifConst::Pcap::snaplen);

if (!pd)
{
    Error("error for pcap\_open\_dead");
    return;
}

if (props.path.empty())
{
    Error("no filename given");
    return;
}

struct stat s;
int exists = 0;

if (append)
{
    // See if output file already exists (and is non-empty).
    exists = stat(props.path.c\_str(), &s);

    if (exists < 0 && errno != ENOENT)
    {
        Error(util::fmt("can't stat file %s: %s", props.path.c\_str(), strerror(errno)));
        return;
    }
}

if (!append || exists < 0 || s.st_size == 0)
{
    // Open new file.
    dumper = pcap\_dump\_open(pd, props.path.c\_str());
    if (!dumper)
    {
        Error(pcap\_geterr(pd));
        return;
    }
}

else
{

#ifdef HAVE_PCAP_DUMP_OPEN_APPEND
dumper = pcap_dump_open_append(pd, props.path.c_str());
#else
// Old file and we need to append, which, unfortunately,
// is not supported by libpcap. So, we have to hack a
// little bit, knowing that pcap_dumper_t is, in fact,
// a FILE … 😦
dumper = (pcap_dumper_t*)fopen(props.path.c_str(), “a”);
#endif
if (!dumper)
{
Error(util::fmt(“can’t open dump %s: %s”, props.path.c_str(), strerror(errno)));
return;
}
}

props.open_time = run_state::network_time;
Opened(props);

}



## Analyzer


![image.png](https://img-blog.csdnimg.cn/img\_convert/76495bce0676077e2119484ded85daa6.png#clientId=uce7ab961-f53a-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u1765d083&margin=[object Object]&name=image.png&originHeight=424&originWidth=999&originalType=url&ratio=1&rotation=0&showTitle=false&size=28441&status=done&style=none&taskId=u8a111149-90b9-4e89-bc7a-a948b823a04&title=)  
Zeek的动态分析框架是将分析器树与每个连接相关联。这棵树可以包含任意数量的分析器在各种群体,并且在连接的整个生命周期内都可以进行修改。并且zeek提供了两种关键的能力:


* 独立于端口进行协议分析。通过一组与协议内容匹配的特征,zeek可以通过器payload找到正确的分析器。当特征匹配时会使用对应的分析器。
* 当分析器解析错误的协议时,可以关闭分析器,并且我们可以使用多个分析器。


所有分析器都派生自类`Analyzer`。我们将 分析器树与每个连接相关联,它反映了数据包分析期间的数据流,分析器根据哪些分析器执行其分析。每个数据包首先被传递到树的根节点,该根节点将其(可能转换的)输入传递给它的所有子节点。每个孩子依次将数据传递给其继任者。


根节点必须始终是`TransportLayerAnalyzer`类型。例如`TCP`、`UDP`和`ICMP`分析器。应用层分析器要么派生自`TCP_ApplicationAnalyzer`(对于TCP 协议),要么派生自通用Analyzer类(对于所有非TCP 协议)。


当连接开始时,初始分析器树由全局`analyzer::Manager`实例化。初始树始终包含相应的`TransportLayerAnalyzer`。对于TCP和UDP,它还分别包含PIA\_TCP或PIA\_UDP类的实例。PIA 负责在连接进行时检测协议。最重要的是,它们执行签名匹配。根据是否使用任何已知端口,初始树可能立即包含也可能不包含任何应用层分析器。


分析器可以支持两种输入方法之一(或两者):分组方式或流方式。分析器可以通过一种方法(例如,分组方式)接受输入,并通过另一种方法(例如,流方式)将其传递给它的孩子。例如TCP\_Analyzer将数据包重新组合成字节流,因此所有TCP\_ApplicationAnalyzer只能看到流式输入。



### Analyzer的接口



// 初始化analyzer
void Init()

// 清楚analyer
void Done()

//分组输入接口
// len 数据长度
// data 指向数据的指针
// orig 数据来自连接发起者为true
// seq 数据相关的序号,如果没有则为-1
// ip 如果有IP相关的数据包头,如果没有则为空
// caplen ip的长度?
void DeliverPacket(int len, const u_char\* data, bool orig, uint64 seq, const IP_Hdr\* ip, int caplen)
    
// 流式输入的接口 
// len 数据长度
// data 指向数据的指针
// orig 数据来自连接发起者为true
void DeliverStream(int len, const u_char\* data, bool orig)
    
// 取消seq的报文
void Undelivered(uint64 seq, int len, bool orig)
// 返回分析器当前使用的内存字节数。
unsigned int MemoryAllocation() const
// 返回分析器类的新实例
static Analyzer\* InstantiateAnalyzer(Connection\* conn)
// 如果分析器完全禁用并且不考虑任何连接,则返回 false。(通常情况下,如果没有为分析器定义事件处理程序,就会出现这种情况。)
static bool Available()
// 给定的端点是否已经传输完成
void EndpointEOF(bool is_orig)
// 每当端点进入TCP\_CLOSED或TCP\_RESET时调用。
void ConnectionFinished(int half_finished)
// 连接重置时调用 
void ConnectionReset()
// 每当看到RST数据包时调用(有时调用 ConnectionReset会延迟)
void PacketWithRST()

Analyzer如果构建?  
Analyzer如何调度,如何形成链式?  
 


## Connection


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pPXGuU0z-1660489984252)(https://cdn.nlark.com/yuque/\_\_puml/544ea3f957a363da4150f42434905c49.svg#lake\_card\_v2=eyJ0eXBlIjoicHVtbCIsImNvZGUiOiJAc3RhcnR1bWxcblxuY2xhc3MgT2JqIHtcblx0XG59XG5cblxuQGVuZHVtbCIsInVybCI6Imh0dHBzOi8vY2RuLm5sYXJrLmNvbS95dXF1ZS9fX3B1bWwvNTQ0ZWEzZjk1N2EzNjNkYTQxNTBmNDI0MzQ5MDVjNDkuc3ZnIiwiaWQiOiJRTTdFViIsIm1hcmdpbiI6eyJ0b3AiOnRydWUsImJvdHRvbSI6dHJ1ZX0sImNhcmQiOiJkaWFncmFtIn0=)]


## 启动



### run\_loop



void run_loop()
{
util::detail::set_processing_status(“RUNNING”, “run_loop”);

iosource::Manager::ReadySources ready;
ready.reserve(iosource_mgr->TotalSize());

while (iosource_mgr->Size() || (BifConst::exit_only_after_terminate && !terminating))
{
    time_updated = false;
    iosource_mgr->FindReadySources(&ready);

#ifdef DEBUG
static int loop_counter = 0;

    // If no source is ready, we log only every 100th cycle,
    // starting with the first.
    if (!ready.empty() || loop_counter++ % 100 == 0)
    {
        DBG\_LOG(DBG_MAINLOOP, "realtime=%.6f ready\_count=%zu", util::current\_time(), ready.size());

        if (!ready.empty())
            loop_counter = 0;
    }

#endif
current_iosrc = nullptr;
auto communication_enabled = broker_mgr->Active();

    if (!ready.empty())
    {
        for (const auto& src : ready)
        {
            auto\* iosrc = src.src;

            DBG\_LOG(DBG_MAINLOOP, "processing source %s", iosrc->Tag());
            current_iosrc = iosrc;
            if (iosrc->ImplementsProcessFd() && src.fd != -1)
                iosrc->ProcessFd(src.fd, src.flags);
            else
                iosrc->Process();
        }
    }
    else if ((have_pending_timers || communication_enabled || BifConst::exit_only_after_terminate) && !pseudo_realtime)
    {
        // Take advantage of the lull to get up to
        // date on timers and events. Because we only
        // have timers as sources, going to sleep here
        // doesn't risk blocking on other inputs.
        update\_network\_time(util::current\_time());
        expire\_timers();
    }

    // Ensure that the time gets updated every pass if we're reading live.
    // This is necessary for e.g. packet sources that don't have a selectable
    // file descriptor. They'll always be ready on a very short timeout, but
    // won't necessarily have a packet to process. In these case, sometimes
    // the time won't get updated for a long time and timers don't function
    // correctly.
    if ((!time_updated && reading_live))
    {
        update\_network\_time(util::current\_time());
        expire\_timers();
    }

    event_mgr.Drain();

    processing_start_time = 0.0; // = "we're not processing now"
    current_dispatched = 0;
    current_iosrc = nullptr;

    if (::signal_val == SIGTERM || ::signal_val == SIGINT)
        // We received a signal while processing the
        // current packet and its related events.
        // Should we put the signal handling into an IOSource?
        zeek\_terminate\_loop("received termination signal");

    if (!reading_traces)
        // Check whether we have timers scheduled for
        // the future on which we need to wait.
        have_pending_timers = zeek::detail::timer_mgr->Size() > 0;

    if (pseudo_realtime && communication_enabled)
    {
        auto have_active_packet_source = false;

        iosource::PktSrc\* ps = iosource_mgr->GetPktSrc();
        if (ps && ps->IsOpen())
            have_active_packet_source = true;

        if (!have_active_packet_source)
            // Can turn off pseudo realtime now
            pseudo_realtime = 0.0;
    }
}

// Get the final statistics now, and not when finish\_run() is
// called, since that might happen quite a bit in the future
// due to expiring pending timers, and we don't want to ding
// for any packets dropped beyond this point.
get\_final\_stats();

}



### Process



void PktSrc::Process()
{
if (!IsOpen())
return;

if (!ExtractNextPacketInternal())
    return;

run_state::detail::dispatch\_packet(&current_packet, this);

have_packet = false;
DoneWithPacket();

}



#### ExtractNextPacketInternal



bool PktSrc::ExtractNextPacketInternal()
{
if (have_packet)
return true;

have_packet = false;

// Don't return any packets if processing is suspended (except for the
// very first packet which we need to set up times).
if (run_state::is\_processing\_suspended() && run_state::detail::first_timestamp)
    return false;

if (run_state::pseudo_realtime)
    run_state::detail::current_wallclock = util::current\_time(true);

if (ExtractNextPacket(&current_packet))
{
    if (current_packet.time < 0)
    {
        Weird("negative\_packet\_timestamp", &current_packet);
        return false;
    }

    if (!run_state::detail::first_timestamp)
        run_state::detail::first_timestamp = current_packet.time;

    have_packet = true;
    return true;
}

if (run_state::pseudo_realtime && !IsOpen())
{
    if (broker_mgr->Active())
        iosource_mgr->Terminate();
}

return false;

}

bool PcapSource::ExtractNextPacket(Packet* pkt)
{
if (!pd)
return false;

const u_char\* data;
pcap_pkthdr\* header;

int res = pcap\_next\_ex(pd, &header, &data);

switch (res)
{
case PCAP_ERROR_BREAK: // -2
    // Exhausted pcap file, no more packets to read.
    assert(!props.is_live);
    Close();
    return false;
case PCAP_ERROR: // -1
    // Error occurred while reading the packet.
    if (props.is_live)
        reporter->Error("failed to read a packet from %s: %s", props.path.data(), pcap\_geterr(pd));
    else
        reporter->FatalError("failed to read a packet from %s: %s", props.path.data(), pcap\_geterr(pd));
    return false;
case 0:
    // Read from live interface timed out (ok).
    return false;
case 1:
    // Read a packet without problem.
    // Although, some libpcaps may claim to have read a packet, but either did
    // not really read a packet or at least provide no way to access its
    // contents, so the following check for null-data helps handle those cases.
    if (!data)
    {
        reporter->Weird("pcap\_null\_data\_packet");
        return false;
    }
    break;
default:
    reporter->InternalError("unhandled pcap\_next\_ex return value: %d", res);
    return false;
}

pkt->Init(props.link_type, &header->ts, header->caplen, header->len, data);

if (header->len == 0 || header->caplen == 0)
{
    Weird("empty\_pcap\_header", pkt);
    return false;
}

++stats.received;
stats.bytes_received += header->len;

// Some versions of libpcap (myricom) are somewhat broken and will return a duplicate
// packet if there are no more packets available. Namely, it returns the exact same
// packet structure (including the header) out of the library without reinitializing
// any of the values. If we set the header lengths to zero here, we can keep from
// processing it a second time.
header->len = 0;
header->caplen = 0;

return true;

}



#### dispatch\_packet



void dispatch_packet(Packet* pkt, iosource::PktSrc* pkt_src)
{
double t = run_state::pseudo_realtime ? check_pseudo_time(pkt) : pkt->time;

if (!zeek_start_network_time)
{
    zeek_start_network_time = t;

    if (network_time_init)
        event_mgr.Enqueue(network_time_init, Args{});
}

current_iosrc = pkt_src;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored “-Wdeprecated-declarations”
current_pktsrc = pkt_src;
#pragma GCC diagnostic pop

// network\_time never goes back.
update\_network\_time(zeek::detail::timer_mgr->Time() < t ? t : zeek::detail::timer_mgr->Time());
processing_start_time = t;
expire\_timers();

zeek::detail::SegmentProfiler\* sp = nullptr;

if (load_sample)
{
    static uint32\_t load_freq = 0;

    if (load_freq == 0)
        load_freq = uint32\_t(0xffffffff) / uint32\_t(zeek::detail::load_sample_freq);

    if (uint32\_t(util::detail::random\_number() & 0xffffffff) < load_freq)
    {
        // Drain the queued timer events so they're not
        // charged against this sample.
        event_mgr.Drain();

        zeek::detail::sample_logger = new zeek::detail::SampleLogger();
        sp = new zeek::detail::SegmentProfiler(zeek::detail::sample_logger, "load-samp");
    }
}
//处理包
packet_mgr->ProcessPacket(pkt);
event_mgr.Drain();

if (sp)
{
    delete sp;
    delete zeek::detail::sample_logger;
    zeek::detail::sample_logger = nullptr;
}

processing_start_time = 0.0; // = "we're not processing now"
current_dispatched = 0;

if (pseudo_realtime && !first_wallclock)
    first_wallclock = util::current\_time(true);

current_iosrc = nullptr;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored “-Wdeprecated-declarations”
current_pktsrc = nullptr;
#pragma GCC diagnostic pop
}



#### process\_packet



void Manager::ProcessPacket(Packet* packet)
{
#ifdef DEBUG
static size_t counter = 0;
DBG_LOG(DBG_PACKET_ANALYSIS, “Analyzing packet %ld, ts=%.3f…”, ++counter, packet->time);
#endif

zeek::detail::SegmentProfiler prof(detail::segment_logger, "dispatching-packet");
if (pkt_profiler)
    pkt_profiler->ProfilePkt(zeek::run_state::processing_start_time, packet->cap_len);

++num_packets_processed;

bool dumped_packet = false;
if (packet->dump_packet || zeek::detail::record_all_packets)
{
    DumpPacket(packet, packet->dump_size);
    dumped_packet = true;
}

// Start packet analysis
root_analyzer->ForwardPacket(packet->cap_len, packet->data, packet, packet->link_type);

if (!packet->processed)
{
    if (packet_not_processed)
        event_mgr.Enqueue(packet_not_processed, Packet::ToVal(packet));

    plugin_mgr->HookUnprocessedPacket(packet);

    if (unprocessed_dumper)
        unprocessed_dumper->Dump(packet);

    total_not_processed++;
}

if (raw_packet)
    event_mgr.Enqueue(raw_packet, packet->ToRawPktHdrVal());

// Check whether packet should be recorded based on session analysis
if (packet->dump_packet && !dumped_packet)
    DumpPacket(packet, packet->dump_size);

}



#### ForwardPacket



bool Analyzer::ForwardPacket(size_t len, const uint8_t* data, Packet* packet) const
{
AnalyzerPtr inner_analyzer = nullptr;

for (const auto& child : analyzers_to_detect)
{
    if (child->DetectProtocol(len, data, packet))
    {
        DBG\_LOG(DBG_PACKET_ANALYSIS, "Protocol detection in %s succeeded, next layer analyzer is %s", GetAnalyzerName(),
                child->GetAnalyzerName());
        inner_analyzer = child;
        break;
    }
}

if (!inner_analyzer)
    inner_analyzer = default_analyzer;

if (!inner_analyzer)
{
    DBG\_LOG(DBG_PACKET_ANALYSIS, "Analysis in %s stopped, no default analyzer available.", GetAnalyzerName());

    if (report_unknown_protocols)
        Weird("no\_suitable\_analyzer\_found", packet);

    return false;
}

return inner_analyzer->AnalyzePacket(len, data, packet);

}



#### EthernetAnalyzer::AnalyzePacket



bool EthernetAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
{
// Make sure that we actually got an entire ethernet header before trying
// to pull bytes out of it.
if (16 >= len)
{
Weird(“truncated_ethernet_frame”, packet);
return false;
}

// Skip past Cisco FabricPath to encapsulated ethernet frame.
if (data[12] == 0x89 && data[13] == 0x03)
{
    auto constexpr cfplen = 16;

    if (cfplen + 14 >= len)
    {
        Weird("truncated\_link\_header\_cfp", packet);
        return false;
    }

    data += cfplen;
    len -= cfplen;
}

// Get protocol being carried from the ethernet frame.
uint32\_t protocol = (data[12] << 8) + data[13];

packet->eth_type = protocol;
packet->l2_dst = data;
packet->l2_src = data + 6;

// Ethernet II frames
if (protocol >= 1536)
    return ForwardPacket(len - 14, data + 14, packet, protocol);

// Other ethernet frame types
if (protocol <= 1500)
{
    if (16 >= len)
    {
        Weird("truncated\_ethernet\_frame", packet);
        return false;
    }

    // Let specialized analyzers take over for non Ethernet II frames.
    // Note that pdata remains at the start of the ethernet frame.

    AnalyzerPtr eth_analyzer = nullptr;

    if (data[14] == 0xAA && data[15] == 0xAA)
        // IEEE 802.2 SNAP
        eth_analyzer = SNAPAnalyzer;
    else if (data[14] == 0xFF && data[15] == 0xFF)
        // Novell raw IEEE 802.3
        eth_analyzer = NovellRawAnalyzer;
    else
        // IEEE 802.2 LLC
        eth_analyzer = LLCAnalyzer;

    if (eth_analyzer)
        return eth_analyzer->AnalyzePacket(len, data, packet);

    return true;
}

// Undefined (1500 < EtherType < 1536)
Weird("undefined\_ether\_type", packet);
return false;

}



#### IPAnalyzer::AnalyzePacket



bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
{
// Check to make sure we have enough data left for an IP header to be here. Note we only
// check ipv4 here. We’ll check ipv6 later once we determine we have an ipv6 header.
if (len < sizeof(struct ip))
{
Weird(“truncated_IP”, packet);
return false;
}

int32\_t hdr_size = static\_cast<int32\_t>(data - packet->data);

// Cast the current data pointer to an IP header pointer so we can use it to get some
// data about the header.
auto ip = (const struct ip\*)data;
uint32\_t protocol = ip->ip_v;

// This is a unique pointer because of the mass of early returns from this method.
if (protocol == 4)
{
    packet->ip_hdr = std::make\_shared<IP\_Hdr>(ip, false);
    packet->l3_proto = L3_IPV4;
}
else if (protocol == 6)
{
    if (len < sizeof(struct ip6\_hdr))
    {
        Weird("truncated\_IP", packet);
        return false;
    }

    packet->ip_hdr = std::make\_shared<IP\_Hdr>((const struct ip6\_hdr\*)data, false, len);
    packet->l3_proto = L3_IPV6;
}
else
{
    Weird("unknown\_ip\_version", packet);
    return false;
}

// If there's an encapsulation stack in this packet, meaning this packet is part of a chain
// of tunnels, make sure to store the IP header in the last flow in the stack so it can be
// used by previous analyzers as we return up the chain.
if (packet->encap)
{
    if (auto\* ec = packet->encap->Last())
        ec->ip_hdr = packet->ip_hdr;
}

const struct ip\* ip4 = packet->ip_hdr->IP4\_Hdr();

// TotalLen() returns the full length of the IP portion of the packet, including
// the IP header and payload.
uint32\_t total_len = packet->ip_hdr->TotalLen();
if (total_len == 0)
{
    // TCP segmentation offloading can zero out the ip\_len field.
    Weird("ip\_hdr\_len\_zero", packet);

    if (detail::ignore_checksums)
        // Cope with the zero'd out ip\_len field by using the caplen.
        total_len = packet->cap_len - hdr_size;
    else
        // If this is caused by segmentation offloading, the checksum will
        // also be incorrect. If checksum validation is enabled - jus tbail here.
        return false;
}

if (packet->len < total_len + hdr_size)
{
    Weird("truncated\_IPv6", packet);
    return false;
}

// For both of these it is safe to pass ip\_hdr because the presence
// is guaranteed for the functions that pass data to us.
uint16\_t ip_hdr_len = packet->ip_hdr->HdrLen();
if (ip_hdr_len > total_len)
{
    Weird("invalid\_IP\_header\_size", packet);
    return false;
}

if (ip_hdr_len > len)
{
    Weird("internally\_truncated\_header", packet);
    return false;
}

if (packet->ip_hdr->IP4\_Hdr())
{
    if (ip_hdr_len < sizeof(struct ip))
    {
        Weird("IPv4\_min\_header\_size", packet);
        return false;
    }
}
else
{
    if (ip_hdr_len < sizeof(struct ip6\_hdr))
    {
        Weird("IPv6\_min\_header\_size", packet);
        return false;
    }
}

// Ignore if packet matches packet filter.
detail::PacketFilter\* packet_filter = packet_mgr->GetPacketFilter(false);
if (packet_filter && packet_filter->Match(packet->ip_hdr, total_len, len))
    return false;

if (!packet->l2_checksummed && !detail::ignore_checksums && ip4
    && !IPBasedAnalyzer::GetIgnoreChecksumsNets()->Contains(packet->ip_hdr->IPHeaderSrcAddr())
    && detail::in\_cksum(reinterpret\_cast<const uint8\_t\*>(ip4), ip_hdr_len) != 0xffff)
{
    Weird("bad\_IP\_checksum", packet);
    return false;
}

if (discarder && discarder->NextPacket(packet->ip_hdr, total_len, len))
    return false;

detail::FragReassembler\* f = nullptr;

if (packet->ip_hdr->IsFragment())
{
    packet->dump_packet = true; // always record fragments

    if (len < total_len)
    {
        Weird("incompletely\_captured\_fragment", packet);

        // Don't try to reassemble, that's doomed.
        // Discard all except the first fragment (which
        // is useful in analyzing header-only traces)
        if (packet->ip_hdr->FragOffset() != 0)
            return false;
    }
    else
    {
        f = detail::fragment_mgr->NextFragment(run_state::processing_start_time, packet->ip_hdr, packet->data + hdr_size);
        std::shared_ptr<IP_Hdr> ih = f->ReassembledPkt();

        if (!ih)
            // It didn't reassemble into anything yet.
            return true;

        ip4 = ih->IP4\_Hdr();

        // Switch the stored ip header over to the one from the
        // fragmented packet.
        packet->ip_hdr = std::move(ih);

        len = total_len = packet->ip_hdr->TotalLen();
        ip_hdr_len = packet->ip_hdr->HdrLen();
        packet->cap_len = total_len + hdr_size;

        if (ip_hdr_len > total_len)
        {
            Weird("invalid\_IP\_header\_size", packet);
            return false;
        }
    }
}

detail::FragReassemblerTracker frt(f);

// We stop building the chain when seeing IPPROTO\_ESP so if it's
// there, it's always the last.
if (packet->ip_hdr->LastHeader() == IPPROTO_ESP)
{
    packet->dump_packet = true;
    if (esp_packet)
        event_mgr.Enqueue(esp_packet, packet->ip_hdr->ToPktHdrVal());

    // Can't do more since upper-layer payloads are going to be encrypted.
    return true;
}

// We stop building the chain when seeing IPPROTO\_MOBILITY so it's always
// last if present.
if (packet->ip_hdr->LastHeader() == IPPROTO_MOBILITY)
{
    packet->dump_packet = true;

    if (!detail::ignore_checksums && mobility\_header\_checksum(packet->ip_hdr.get()) != 0xffff)
    {
        Weird("bad\_MH\_checksum", packet);
        return false;
    }

    if (mobile_ipv6_message)
        event_mgr.Enqueue(mobile_ipv6_message, packet->ip_hdr->ToPktHdrVal());

    if (packet->ip_hdr->NextProto() != IPPROTO_NONE)
        Weird("mobility\_piggyback", packet);

    return true;
}

// Set the data pointer to match the payload from the IP header. This makes sure that it's also
// pointing at the reassembled data for a fragmented packet.
data = packet->ip_hdr->Payload();
len -= ip_hdr_len;

// Session analysis assumes that the header size stored in the packet does not include the IP
// header size. There are two reasons for this: 1) Packet::ToRawPktHdrVal() wants to look at the
// IP header for reporting, and 2) The VXLAN analyzer uses the header position to create the
// next packet in the tunnel chain. Once the TCP/UDP work is done and the VXLAN analyzer can
// move into packet analysis, this can change, but for now we leave it as it is.

bool return_val = true;
int proto = packet->ip_hdr->NextProto();

packet->proto = proto;

// Double check the lengths one more time before forwarding this on.
if (total_len < packet->ip_hdr->HdrLen())
{
    Weird("bogus\_IP\_header\_lengths", packet);
    return false;
}

switch (proto)
{
case IPPROTO_NONE:
    // If the packet is encapsulated in Teredo, then it was a bubble and
    // the Teredo analyzer may have raised an event for that, else we're
    // not sure the reason for the No Next header in the packet.
    if (!(packet->encap && packet->encap->LastType() == BifEnum::Tunnel::TEREDO))
    {
        Weird("ipv6\_no\_next", packet);
        return_val = false;
    }
    break;
default:
    packet->proto = proto;

    // For everything else, pass it on to another analyzer. If there's no one to handle
    // that, it'll report a Weird.
    return_val = ForwardPacket(len, data, packet, proto);
    break;
}

if (f)
    f->DeleteTimer();

return return_val;

}



#### IPBasedAnalyzer::AnalyzePacket



bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt)
{
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);
    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;

conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel());

zeek::ValPtr pkt_hdr_val;

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;

// If the packet is reassembled, disable packet dumping because the
// pointer math to dump the data wouldn't work.
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;

}



#### IPBasedAnalyzer::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\* 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;

}



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

img
img
img

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

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

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

we know.
if (!analyzers_by_port.empty() && !zeek::detail::dpd_ignore_ports)
{
int resp_port = ntohs(conn->RespPort());
std::setzeek::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);
            }
        }
    }
}

[外链图片转存中…(img-o6uC6v3F-1715574226017)]
[外链图片转存中…(img-4EJQi9Gx-1715574226017)]
[外链图片转存中…(img-SHJmDkWp-1715574226018)]

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

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

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

  • 17
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值