2024年Go最新Zeek学习(四) —— IP协议解析_zeek 协议识别(4),2024年最新Golang开发中遇到最难的问题

img
img

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

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

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

            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 )
            // 如果不是重组包则直接返回,一般走不到这里
            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);

// 停止构建IPV6链
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;
}

data = packet->ip_hdr->Payload();
len -= ip_hdr_len;

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 ( ! (packet->encap && packet->encap->LastType() == BifEnum::Tunnel::TEREDO) )
        {
            Weird("ipv6\_no\_next", packet);
            return_val = false;
        }
        break;
    default:
        packet->proto = proto;
        
       // 传递给下一个包处理器
        return_val = ForwardPacket(len, data, packet, proto);
        break;
}

// 删除重组定时器
if ( f )
    f->DeleteTimer();

return return_val;
}


### IP\_Hdr



class IP_Hdr
{
public:
// 构造函数
IP_Hdr(const struct ip* arg_ip4, bool arg_del, bool reassembled = false);
// 构造函数
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del, int len, const IPv6_Hdr_Chain* c = nullptr,
bool reassembled = false);
//拷贝方法
IP_Hdr* Copy() const;
// 析构
~IP_Hdr();
// 获取原始IPV4结构
const struct ip* IP4_Hdr() const { return ip4; }
// 获取原始IPV6结构
const struct ip6_hdr* IP6_Hdr() const { return ip6; }

IPAddr IPHeaderSrcAddr() const;
IPAddr IPHeaderDstAddr() const;
IPAddr SrcAddr() const;
IPAddr DstAddr() const;
// IP层负载指针
const u_char\* Payload() const;
// 移动头
const ip6_mobility\* MobilityHeader() const
// 负载长度,IPV4启用TCP分段时返回0
uint16\_t PayloadLen() const
//IP报文总长度(header+payload)
uint32\_t TotalLen() const
// IP头长度
uint16\_t HdrLen() const { return ip4 ? ip4->ip_hl \* 4 : ip6_hdrs->TotalLength(); }
// IPV6的最后一个头部
uint8\_t LastHeader() const
// 传输层协议类型
unsigned char NextProto() const
// TTL
unsigned char TTL() const { return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; }
// IP报文是否分段
bool IsFragment() const
// 当前分段报文的偏移字节数
uint16\_t FragOffset() const
// 标识
uint32\_t ID() const { return ip4 ? ntohs(ip4->ip_id) : ip6_hdrs->ID(); }
// more fragment是否设置
int MF() const { return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : ip6_hdrs->MF(); }
// 不分段是否设置
int DF() const { return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; }
// IPV6流标签
uint32\_t FlowLabel() const { return ip4 ? 0 : (ntohl(ip6->ip6_flow) & 0x000fffff); }
// IPV6拓展头的数量
size_t NumHeaders() const { return ip4 ? 1 : ip6_hdrs->Size(); }
// 返回头部记录值对象指针
RecordValPtr ToIPHdrVal() const;
// 返回报记录值对象指针(包括IP头部和下一层头部)
RecordValPtr ToPktHdrVal() const;
// 和上个方法一样
RecordValPtr ToPktHdrVal(RecordValPtr pkt_hdr, int sindex) const;

bool Reassembled() const { return reassembled; }

private:
const struct ip\* ip4 = nullptr;
const struct ip6\_hdr\* ip6 = nullptr;
const IPv6_Hdr_Chain\* ip6_hdrs = nullptr;
bool del = false;
bool reassembled = false;
};


### IP分片


1. 首先将源地址、目的地址、段ID使用make\_tuple形成key
2. 然后查找此key是否存在,不存在就创建一个并添加到map中
3. 然后再把当前包添加到重组对象中



FragReassembler* FragmentManager::NextFragment(double t, const std::shared_ptr<IP_Hdr>& ip,
const u_char* pkt)
{
uint32_t frag_id = ip->ID();
FragReassemblerKey key = std::make_tuple(ip->SrcAddr(), ip->DstAddr(), frag_id);

FragReassembler\* f = nullptr;
auto it = fragments.find(key);
if ( it != fragments.end() )
	f = it->second;

if ( ! f )
	{
	f = new FragReassembler(session_mgr, ip, pkt, key, t);
	fragments[key] = f;
	if ( fragments.size() > max_fragments )
		max_fragments = fragments.size();
	return f;
	}

f->AddFragment(t, ip, pkt);
return f;
}


#### FragManager



class FragmentManager
{
public:
FragmentManager() = default;
~FragmentManager();
// 添加分片
FragReassembler* NextFragment(double t, const std::shared_ptr<IP_Hdr>& ip, const u_char* pkt);
// 清空分片
void Clear();
// 移除分片
void Remove(detail::FragReassembler* f);

size_t Size() const { return fragments.size(); }
size_t MaxFragments() const { return max_fragments; }
[[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See "
             "GHI-572.")]] uint32\_t
    MemoryAllocation() const;

private:
using FragmentMap = std::map<detail::FragReassemblerKey, detail::FragReassembler*>;
FragmentMap fragments;
size_t max_fragments = 0;
};



#### FragReassembler



class FragReassembler : public Reassembler
{
public:
FragReassembler(session::Manager* s, const std::shared_ptr<IP_Hdr>& ip, const u_char* pkt,
const FragReassemblerKey& k, double t);
~FragReassembler() override;

void AddFragment(double t, const std::shared_ptr<IP_Hdr>& ip, const u_char\* pkt);

void Expire(double t);
void DeleteTimer();
void ClearTimer() { expire_timer = nullptr; }

std::shared_ptr<IP_Hdr> ReassembledPkt() { return std::move(reassembled_pkt); }
const FragReassemblerKey& Key() const { return key; }

protected:
void BlockInserted(DataBlockMap::const_iterator it) override;
void Overlap(const u_char* b1, const u_char* b2, uint64_t n) override;
void Weird(const char* name) const;

// IP头部,使用memcpy
u_char\* proto_hdr;
// 
std::shared_ptr<IP_Hdr> reassembled_pkt;
session::Manager\* s;
// 完全重组后包的大小
uint64\_t frag_size;
// key
FragReassemblerKey key;
 // 第一个IPV6段的下一个协议字段
uint16\_t next_proto;
// 协议头长度
uint16\_t proto_hdr_len;

FragTimer\* expire_timer;

};



##### 构造函数


1. 拷贝IP头部信息
2. 启动定时器
3. 调用AddFragment



FragReassembler::FragReassembler(session::Manager* arg_s, const std::shared_ptr<IP_Hdr>& ip,
const u_char* pkt, const FragReassemblerKey& k, double t)
: Reassembler(0, REASSEM_FRAG)
{
s = arg_s;
key = k;

    const struct ip\* ip4 = ip->IP4\_Hdr();
    if ( ip4 )
    {
        proto_hdr_len = ip->HdrLen();
        proto_hdr = new u_char[64]; // max IP header + slop
        // Don't do a structure copy - need to pick up options, too.
        memcpy((void\*)proto_hdr, (const void\*)ip4, proto_hdr_len);
    }
    else
    {
        proto_hdr_len = ip->HdrLen() - 8; // minus length of fragment header
        proto_hdr = new u_char[proto_hdr_len];
        memcpy(proto_hdr, ip->IP6\_Hdr(), proto_hdr_len);
    }
    
    reassembled_pkt = nullptr;
    frag_size = 0; // flag meaning "not known"
    next_proto = ip->NextProto();
    
    if ( frag_timeout != 0.0 )
    {
        expire_timer = new FragTimer(this, t + frag_timeout);
        timer_mgr->Add(expire_timer);
    }
    else
        expire_timer = nullptr;
    
    AddFragment(t, ip, pkt);
}


##### AddFragment


1. 对协议和头部长度进行检查
2. 对协议的DF进行检查
3. 对头部和总长度进行检查
4. 判断是否有更多分片MF,如果没有设置总大小



void FragReassembler::AddFragment(double t, const std::shared_ptr<IP_Hdr>& ip, const u_char* pkt)
{
const struct ip* ip4 = ip->IP4_Hdr();
// 对协议和头部长度进行检查
if ( ip4 )
{
if ( ip4->ip_p != ((const struct ip*)proto_hdr)->ip_p ||
ip4->ip_hl != ((const struct ip*)proto_hdr)->ip_hl )
// || ip4->ip_tos != proto_hdr->ip_tos
// don’t check TOS, there’s at least one stack that actually
// uses different values, and it’s hard to see an associated
// attack.
s->Weird(“fragment_protocol_inconsistency”, ip.get());
}
else
{
if ( ip->NextProto() != next_proto || ip->HdrLen() - 8 != proto_hdr_len )
s->Weird(“fragment_protocol_inconsistency”, ip.get());
// TODO: more detailed unfrag header consistency checks?
}
// 对DF进行检查
if ( ip->DF() )
// Linux MTU discovery for UDP can do this, for example.
s->Weird(“fragment_with_DF”, ip.get());

uint16\_t offset = ip->FragOffset();
uint32\_t len = ip->TotalLen();
uint16\_t hdr_len = ip->HdrLen();
// 对头部和总长度进行检查
if ( len < hdr_len )
{
    s->Weird("fragment\_protocol\_inconsistency", ip.get());
    return;
}
// 计算总带下 = 当前分片偏移值+当前IP报总长度 - 当前IP报头部长度
uint64\_t upper_seq = offset + len - hdr_len;
// IPV6
if ( ! offset )
    // Make sure to use the first fragment header's next field.
    next_proto = ip->NextProto();
// 判断是否有更多分片MF
if ( ! ip->MF() )
{
    // Last fragment.
    if ( frag_size == 0 )
        // 设置总大小
        frag_size = upper_seq;
    
    else if ( upper_seq != frag_size )
    {
        s->Weird("fragment\_size\_inconsistency", ip.get());
        
        if ( upper_seq > frag_size )
            frag_size = upper_seq;
    }
}

else if ( len < MIN_ACCEPTABLE_FRAG_SIZE )
    s->Weird("excessively\_small\_fragment", ip.get());

if ( upper_seq > MAX_ACCEPTABLE_FRAG_SIZE )
    s->Weird("excessively\_large\_fragment", ip.get());

if ( frag_size && upper_seq > frag_size )
{
    // This can happen if we receive a fragment that's \*not\*
    // the last fragment, but still imputes a size that's
    // larger than the size we derived from a previously-seen
    // "last fragment".
    
    s->Weird("fragment\_size\_inconsistency", ip.get());
    frag_size = upper_seq;
}

// Do we need to check for consistent options? That's tricky
// for things like LSRR that get modified in route.

// Remove header.
pkt += hdr_len;
len -= hdr_len;

NewBlock(run_state::network_time, offset, len, pkt);

}



##### NewBlock



seq: offset
len: 当前IP报文 - 头部长度
data:当前IP报文的负载
void Reassembler::NewBlock(double t, uint64_t seq, uint64_t len, const u_char* data)
{
if ( len == 0 )
return;
// 当前负载长度/总长度
uint64_t upper_seq = seq + len;

// 第一次的包直接返回
CheckOverlap(old_block_list, seq, len, data);

if ( upper_seq <= trim_seq )
    // Old data, don't do any work for it.
    return;

// 第一次的包直接返回
CheckOverlap(block_list, seq, len, data);

// 部分旧数据,保存旧数据
if ( seq < trim_seq )
{ // Partially old data, just keep the good stuff.
    uint64\_t amount_old = trim_seq - seq;
    
    data += amount_old;
    seq += amount_old;
    len -= amount_old;
}

auto it = block_list.Insert(seq, upper_seq, data);
;
BlockInserted(it);

}

seq: offset
len: 当前IP报文 - 头部长度
data:当前IP报文的负载
void Reassembler::CheckOverlap(const DataBlockList& list, uint64_t seq, uint64_t len,
const u_char* data)
{
if ( list.Empty() )
return;

const auto& last = list.LastBlock();

if ( seq == last.upper )
    // Special case check for common case of appending to the end.
    return;

uint64\_t upper = (seq + len);

auto it = list.FirstBlockAtOrBefore(seq);

if ( it == list.End() )
    it = list.Begin();

for ( ; it != list.End(); ++it )
{
    const auto& b = it->second;
    uint64\_t nseq = seq;
    uint64\_t nupper = upper;
    const u_char\* ndata = data;
    
    if ( nupper <= b.seq )
        break;
    
    if ( nseq >= b.upper )
        continue;
    
    if ( nseq < b.seq )
    {
        ndata += (b.seq - seq);
        nseq = b.seq;
    }
    
    if ( nupper > b.upper )
        nupper = b.upper;
    
    uint64\_t overlap_offset = (nseq - b.seq);
    uint64\_t overlap_len = (nupper - nseq);
    
    if ( overlap_len )
        Overlap(&b.block[overlap_offset], ndata, overlap_len);
}

}

DataBlockMap::const_iterator DataBlockList::Insert(uint64_t seq, uint64_t upper, const u_char* data,
DataBlockMap::const_iterator hint)
{
auto size = upper - seq;
auto rval = block_map.emplace_hint(hint, seq, DataBlock(data, size, seq));

total_data_size += size;
Reassembler::sizes[reassembler->rtype] += size + sizeof(DataBlock);
Reassembler::total_size += size + sizeof(DataBlock);

return rval;
}

seq: offset
uppper:seq + len 当前负载长度/总长度
data:当前IP报文的负载
DataBlockMap::const_iterator DataBlockList::Insert(uint64_t seq, uint64_t upper, const u_char* data,
DataBlockMap::const_iterator* hint)
{
// Empty list.
if ( block_map.empty() )
return Insert(seq, upper, data, block_map.end());

const auto& last = block_map.rbegin()->second;

// Special check for the common case of appending to the end.
if ( seq == last.upper )
	return Insert(seq, upper, data, block_map.end());

img
img
img

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

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

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

	return Insert(seq, upper, data, block_map.end());

const auto& last = block_map.rbegin()->second;

// Special check for the common case of appending to the end.
if ( seq == last.upper )
	return Insert(seq, upper, data, block_map.end());

[外链图片转存中…(img-Rb4fFda8-1715640795265)]
[外链图片转存中…(img-Cotxw6vz-1715640795266)]
[外链图片转存中…(img-3gfZZY9b-1715640795266)]

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值