• Zeek学习(四) —— IP协议解析


    IP

    IP层的解析主要位于src/packet_analysis/ip/IP.ccIPAnalyzer::AnalyzePacket中,其涉及结构体主要包括:

    • Packet:包信息
    • struct ip:netinet/ip.h中定义的IP头部
    • struct ip6_hdr:netinet/ip6.h中定义的IPV6头部
    • IP_Hdr:自定义的IP头部类
    • detail::PacketFilter:包过滤
    • zeek::detail::Discarder:报是否需要丢弃
    • detail::FragmentManager
    // 参数输入
    // len 数据长度(即除ether层的数据长度)
    // data 数据
    // packet Packet对象
    bool IPAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
    {
        // 首先对长度进行校验,如果长度小于IP的头部则代表这个包是非法的报文直接返回
        if ( len < sizeof(struct ip) )
        {
            Weird("truncated_IP", packet);
            return false;
        }
        
        // 获取头部数据大小
        int32_t hdr_size = static_cast<int32_t>(data - packet->data);
        
        // 强转成IP头部
        auto ip = (const struct ip*)data;
        // 协议
        uint32_t protocol = ip->ip_v;
        
        
        if ( protocol == 4 )
        {   
            // 将ip头部转化成IP_Hdr对象
            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;
            }
            // 将ip头部转化成IP_Hdr对象
            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;
        }
        
        //如果在这个包中有一个封装栈,意味着这个包是链的一部分隧道,确保将IP头存储在堆栈的最后一个流中,
        //以便它可以之前的分析器在我们返回链时使用。
        if ( packet->encap )
        {
            if ( auto* ec = packet->encap->Last() )
                ec->ip_hdr = packet->ip_hdr;
        }
        
        const struct ip* ip4 = packet->ip_hdr->IP4_Hdr();
        
        //获取总长度,一般和len一样
        uint32_t total_len = packet->ip_hdr->TotalLen();
        if ( total_len == 0 )
        {
           // 处理解析出来的总长度大小为0的情况,一般都不会进入到这里面
            Weird("ip_hdr_len_zero", packet);
            
            if ( detail::ignore_checksums )
                total_len = packet->cap_len - hdr_size;
            else
                return false;
        }
        
        // 截断IPV6?不太明白
        if ( packet->len < total_len + hdr_size )
        {
            Weird("truncated_IPv6", packet);
            return false;
        }
       
        // 获取IP头部
        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;
            }
        }
        
        // 包过滤
        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);
                /// 不完整的分片
                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 )
                    // 如果不是重组包则直接返回,一般走不到这里
                    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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243

    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;
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    构造函数

    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);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    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());
    
    	// Find the first block that doesn't come completely before the new data.
    	DataBlockMap::const_iterator it;
    
    	if ( hint )
    		it = *hint;
    	else
    		{
    		it = FirstBlockAtOrBefore(seq);
    
    		if ( it == block_map.end() )
    			it = block_map.begin();
    		}
    
    	while ( std::next(it) != block_map.end() && it->second.upper <= seq )
    		++it;
    
    	const auto& b = it->second;
    
    	if ( b.upper <= seq )
    		// b is the last block, and it comes completely before the new block.
    		return Insert(seq, upper, data, block_map.end());
    
    	if ( upper <= b.seq )
    		// The new block comes completely before b.
    		return Insert(seq, upper, data, it);
    
    	DataBlockMap::const_iterator rval;
    
    	// The blocks overlap.
    	if ( seq < b.seq )
    		{
    		// The new block has a prefix that comes before b.
    		uint64_t prefix_len = b.seq - seq;
    
    		rval = Insert(seq, seq + prefix_len, data, it);
    
    		data += prefix_len;
    		seq += prefix_len;
    		}
    	else
    		rval = it;
    
    	uint64_t overlap_start = seq;
    	uint64_t overlap_offset = overlap_start - b.seq;
    	uint64_t new_b_len = upper - seq;
    	uint64_t b_len = b.upper - overlap_start;
    	uint64_t overlap_len = min(new_b_len, b_len);
    
    	if ( overlap_len < new_b_len )
    		{
    		// Recurse to resolve remainder of the new data.
    		data += overlap_len;
    		seq += overlap_len;
    
    		auto r = Insert(seq, upper, data, &it);
    
    		if ( rval == it )
    			rval = r;
    		}
    
    	return rval;
    	}
    
    DataBlock::DataBlock(const u_char* data, uint64_t size, uint64_t arg_seq)
    	{
    	seq = arg_seq;
    	upper = seq + size;
    	block = new u_char[size];
    	memcpy(block, data, size);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185

    BlockInserted

    void FragReassembler::BlockInserted(DataBlockMap::const_iterator /* it */)
    	{
    	auto it = block_list.Begin();
    
    	if ( it->second.seq > 0 || ! frag_size )
    		// For sure don't have it all yet.
    		return;
    
    	auto next = std::next(it);
    
    	
        // 校验是否所有分片都存在
    	while ( next != block_list.End() )
    		{
    		if ( it->second.upper != next->second.seq )
    			break;
    
    		++it;
    		++next;
    		}
    
    	const auto& last = block_list.LastBlock();
    
    	if ( next != block_list.End() )
    		{
    		// We have a hole.
    		if ( it->second.upper >= frag_size )
    			{
    			// We're stuck.  The point where we stopped is
    			// contiguous up through the expected end of
    			// the fragment, but there's more stuff still
    			// beyond it, which is not contiguous.  This
    			// can happen for benign reasons when we're
    			// intermingling parts of two fragmented packets.
    			Weird("fragment_size_inconsistency");
    
    			// We decide to analyze the contiguous portion now.
    			// Extend the fragment up through the end of what
    			// we have.
    			frag_size = it->second.upper;
    			}
    		else
    			return;
    		}
    
    	else if ( last.upper > frag_size )
    		{
    		Weird("fragment_size_inconsistency");
    		frag_size = last.upper;
    		}
    
    	else if ( last.upper < frag_size )
    		// Missing the tail.
    		return;
    
    	// We have it all.  Compute the expected size of the fragment.
    	uint64_t n = proto_hdr_len + frag_size;
    
    	// It's possible that we have blocks associated with this fragment
    	// that exceed this size, if we saw MF fragments (which don't lead
    	// to us setting frag_size) that went beyond the size indicated by
    	// the final, non-MF fragment.  This can happen for benign reasons
    	// due to intermingling of fragments from an older datagram with those
    	// for a more recent one.
    
    	u_char* pkt = new u_char[n];
    	memcpy((void*)pkt, (const void*)proto_hdr, proto_hdr_len);
    
    	u_char* pkt_start = pkt;
    
    	pkt += proto_hdr_len;
    
    	for ( it = block_list.Begin(); it != block_list.End(); ++it )
    		{
    		const auto& b = it->second;
    
    		if ( it != block_list.Begin() )
    			{
    			const auto& prev = std::prev(it)->second;
    
    			// If we're above a hole, stop.  This can happen because
    			// the logic above regarding a hole that's above the
    			// expected fragment size.
    			if ( prev.upper < b.seq )
    				break;
    			}
    
    		if ( b.upper > n )
    			{
    			reporter->InternalWarning("bad fragment reassembly");
    			DeleteTimer();
    			Expire(run_state::network_time);
    			delete[] pkt_start;
    			return;
    			}
    
    		memcpy(&pkt[b.seq], b.block, b.upper - b.seq);
    		}
    
    	reassembled_pkt.reset();
    
    	unsigned int version = ((const struct ip*)pkt_start)->ip_v;
    
    	if ( version == 4 )
    		{
    		struct ip* reassem4 = (struct ip*)pkt_start;
    		reassem4->ip_len = htons(frag_size + proto_hdr_len);
    		reassembled_pkt = std::make_shared<IP_Hdr>(reassem4, true, true);
    		DeleteTimer();
    		}
    
    	else if ( version == 6 )
    		{
    		struct ip6_hdr* reassem6 = (struct ip6_hdr*)pkt_start;
    		reassem6->ip6_plen = htons(frag_size + proto_hdr_len - 40);
    		const IPv6_Hdr_Chain* chain = new IPv6_Hdr_Chain(reassem6, next_proto, n);
    		reassembled_pkt = std::make_shared<IP_Hdr>(reassem6, true, n, chain, true);
    		DeleteTimer();
    		}
    
    	else
    		{
    		reporter->InternalWarning("bad IP version in fragment reassembly: %d", version);
    		delete[] pkt_start;
    		}
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127

    推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习]

  • 相关阅读:
    动态天气预报:Living Weather HD for Mac
    Android实验三:音乐播放器——图解详细教程
    SpringBoot实践(二十五):后端响应的规范化
    环境准备:虚拟环境搭建
    conda配置完整的pytorch虚拟环境
    理解 iOS 开发中的 NS_ENUM 和 NS_OPTIONS
    电子统计台账:锁定某月台账数据,防止数据丢失
    OpenGL实现GPU体渲染
    基于语雀编辑器的在线文档编辑与查看
    1.5 HDFS分布式文件系统-hadoop-最全最完整的保姆级的java大数据学习资料
  • 原文地址:https://blog.csdn.net/hzb869168467/article/details/126338092