IPv4 checksum in C/C++ Impl

Impl

inline unsigned short                                                           ip_standard_chksum(void* dataptr, int len) noexcept {
                unsigned int acc;
                unsigned short src;
                unsigned char* octetptr;

                acc = 0;
                /* dataptr may be at odd or even addresses */
                octetptr = (unsigned char*)dataptr;
                while (len > 1) {
                    /* declare first octet as most significant
                       thus assume network order, ignoring host order */
                    src = (unsigned short)((*octetptr) << 8);
                    octetptr++;
                    /* declare second octet as least significant */
                    src |= (*octetptr);
                    octetptr++;
                    acc += src;
                    len -= 2;
                }
                if (len > 0) {
                    /* accumulate remaining octet */
                    src = (unsigned short)((*octetptr) << 8);
                    acc += src;
                }
                /* add deferred carry bits */
                acc = (unsigned int)((acc >> 16) + (acc & 0x0000ffffUL));
                if ((acc & 0xffff0000UL) != 0) {
                    acc = (unsigned int)((acc >> 16) + (acc & 0x0000ffffUL));
                }
                /* This maybe a little confusing: reorder sum using htons()
                   instead of ntohs() since it has a little less call overhead.
                   The caller must invert bits for Internet sum ! */
                return ntohs((unsigned short)acc);
            }

            inline unsigned short                                                           inet_chksum(void* dataptr, int len) noexcept {
                return (unsigned short)~ip_standard_chksum(dataptr, len);
            }

            inline unsigned int                                                             FOLD_U32T(unsigned int u) noexcept {
                return ((unsigned int)(((u) >> 16) + ((u) & 0x0000ffffUL)));
            }

            inline unsigned int                                                             SWAP_BYTES_IN_WORD(unsigned int w) noexcept {
                return (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8);
            }

            inline unsigned short                                                           inet_cksum_pseudo_base(unsigned char* payload, unsigned int proto, unsigned int proto_len, unsigned int acc) noexcept {
                bool swapped = false;
                acc += ip_standard_chksum(payload, (int)proto_len);
                acc = FOLD_U32T(acc);

                if (proto_len % 2 != 0) {
                    swapped = !swapped;
                    acc = SWAP_BYTES_IN_WORD(acc);
                }

                if (swapped) {
                    acc = SWAP_BYTES_IN_WORD(acc);
                }

                acc += htons((unsigned short)proto);
                acc += htons((unsigned short)proto_len);

                acc = FOLD_U32T(acc);
                acc = FOLD_U32T(acc);

                return (unsigned short)~(acc & 0xffffUL);
            }

            inline unsigned short                                                           inet_chksum_pseudo(unsigned char* payload, unsigned int proto, unsigned int proto_len, unsigned int src, unsigned int dest) noexcept {
                unsigned int acc;
                unsigned int addr;

                addr = src;
                acc = (addr & 0xffff);
                acc = (acc + ((addr >> 16) & 0xffff));
                addr = dest;
                acc = (acc + (addr & 0xffff));
                acc = (acc + ((addr >> 16) & 0xffff));

                /* fold down to 16 bits */
                acc = FOLD_U32T(acc);
                acc = FOLD_U32T(acc);

                return inet_cksum_pseudo_base(payload, proto, proto_len, acc);
            }

C/C++ Header.

#pragma pack(push, 1)
            struct ip_hdr {
            public:
                enum Flags {
                    IP_RF                                                   = 0x8000,            /* reserved fragment flag */
                    IP_DF                                                   = 0x4000,            /* dont fragment flag */
                    IP_MF                                                   = 0x2000,            /* more fragments flag */
                    IP_OFFMASK                                              = 0x1fff,            /* mask for fragmenting bits */
                };

            public:
                 /* version / header length / type of service */
                 unsigned char                                              v_hl;
                 /* type of service */
                 unsigned char                                              tos;
                 /* total length */
                 unsigned short                                             len;
                 /* identification */
                 unsigned short                                             id;
                 /* fragment offset field */                                
                 unsigned short                                             flags;
                 /* time to live */
                 unsigned char                                              ttl;
                 /* protocol */
                 unsigned char                                              proto;
                 /* checksum */
                 unsigned short                                             chksum;
                 /* source and destination IP addresses */
                 unsigned int                                               src;
                 union {
                    unsigned int                                            dst;
                    unsigned int                                            dest;
                 };

            public:
                static int                                                  IPH_V(struct ip_hdr* hdr) noexcept {
                    return ((hdr)->v_hl >> 4);      
                }       
                static int                                                  IPH_HL(struct ip_hdr* hdr) noexcept {
                    return ((hdr)->v_hl & 0x0f);        
                }       
                static int                                                  IPH_PROTO(struct ip_hdr* hdr) noexcept {
                    return ((hdr)->proto & 0xff);       
                }       
                static int                                                  IPH_OFFSET(struct ip_hdr* hdr) noexcept {
                    return (hdr)->flags;        
                }       
                static int                                                  IPH_TTL(struct ip_hdr* hdr) noexcept {
                    return ((hdr)->ttl & 0xff);
                }

            public:
                static int                                                  Mtu(int mtu, bool v4_or_v6) noexcept {
                    static constexpr int MTU_V4_MIN = 68;
                    static constexpr int MTU_V6_MIN = 1280;

                    if (mtu > ip_hdr::MTU) {
                        mtu = ip_hdr::MTU;
                    }
                    elif(v4_or_v6) {
                        if (mtu < MTU_V4_MIN) {
                            mtu = MTU_V4_MIN;
                        }
                    }
                    elif(mtu < MTU_V6_MIN) {
                        mtu = MTU_V6_MIN;
                    }

                    return mtu;
                }
                static int                                                  Mss(int mtu, bool v4_or_v6) noexcept {
                    mtu = ip_hdr::Mtu(mtu, v4_or_v6);
                    if (v4_or_v6) {
                        return mtu - (ip_hdr::IP_HLEN << 0);
                    }
                    else {
                        return mtu - (ip_hdr::IP_HLEN << 1);
                    }
                }

            public:
                static struct ip_hdr*                                       Parse(const void* packet, int size) noexcept;
                static unsigned short                                       NewId() noexcept;

            public:
                static const int                                            IP_HLEN;
                static const unsigned char                                  IP_DFT_TTL;

            public:
                static constexpr unsigned char                              IP_VER                  = 4;
                static constexpr unsigned int                               IP_ADDR_ANY_VALUE       = INADDR_ANY;
                static constexpr unsigned int                               IP_ADDR_BROADCAST_VALUE = INADDR_BROADCAST;
                static constexpr int                                        TOS_ROUTIN_MODE         = 0;
                static constexpr unsigned char                              IP_PROTO_IP             = 0;
                static constexpr unsigned char                              IP_PROTO_ICMP           = 1;
                static constexpr unsigned char                              IP_PROTO_UDP            = 17;
                static constexpr unsigned char                              IP_PROTO_TCP            = 6;
                static constexpr int                                        MTU                     = 1500;
            };
#pragma pack(pop)

C/C++ Source.

 const int           ip_hdr::IP_HLEN    = sizeof(struct ip_hdr);
            const int           tcp_hdr::TCP_HLEN  = sizeof(struct tcp_hdr);
            const unsigned char ip_hdr::IP_DFT_TTL = Socket::GetDefaultTTL();

            unsigned short ip_hdr::NewId() noexcept
            {
                static std::atomic<unsigned int> aid = ATOMIC_FLAG_INIT;

                for (;;)
                {
                    unsigned short r = ++aid;
                    if (r != 0)
                    {
                        return r;
                    }
                }
            }

            struct ip_hdr* ip_hdr::Parse(const void* packet, int len) noexcept
            {
                struct ip_hdr* iphdr = (struct ip_hdr*)packet;
                if (NULL == iphdr)
                {
                    return NULL;
                }

                int iphdr_ver = IPH_V(iphdr);
                if (iphdr_ver != ip_hdr::IP_VER)
                {
                    return NULL;
                }

                int iphdr_hlen = IPH_HL(iphdr) << 2;
                if (iphdr_hlen > len)
                {
                    return NULL;
                }

                if (iphdr_hlen < IP_HLEN)
                {
                    return NULL;
                }

                int ttl = IPH_TTL(iphdr);
                if (ttl < 1)
                {
                    return NULL;
                }

                if (len != ntohs(iphdr->len))
                {
                    return NULL;
                }

                /* all ones (broadcast) or all zeroes (old skool broadcast) */
                if (iphdr->dest == IP_ADDR_ANY_VALUE)
                {
                    return NULL;
                }

                /* ~iphdr->dest == IP_ADDR_ANY_VALUE */ 
                if (iphdr->src == IP_ADDR_ANY_VALUE || iphdr->src == IP_ADDR_BROADCAST_VALUE) 
                {
                    return NULL;
                }

                // if ((IPH_OFFSET(iphdr) & ntohs((UInt16)(ip_hdr::IP_OFFMASK | ip_hdr::IP_MF)))) 
                // {
                //     return NULL;
                // }

#if defined(PACKET_CHECKSUM)
                if (iphdr->chksum != 0)
                {
                    int checksum = inet_chksum(iphdr, iphdr_hlen);
                    if (checksum != 0)
                    {
                        return NULL;
                    }
                }
#endif

                int proto = IPH_PROTO(iphdr);
                return proto == IP_PROTO_UDP || proto == IP_PROTO_TCP || proto == IP_PROTO_ICMP ? iphdr : NULL;
            }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IPv4数据包的校验和(checksum)是一种用于检测数据传输过程中出现错误的机制。IPv4数据包的校验和是由IPv4首部中的某些字段计算得出的,其中包括源IP地址、目的IP地址、协议类型、数据长度等信息。IPv4数据包的校验和是在发送端计算得出的,并在接收端进行验证。如果接收端计算出的校验和与发送端计算出的校验和不一致,则说明数据在传输过程中出现了错误。 在IPv4数据包中,校验和字段位于IP首部的第10个字节和第11个字节。计算IPv4数据包的校验和需要将IP首部中的所有16位字(除了校验和字段本身)两两相加,然后将结果取反得到最终的校验和。如果计算出的校验和与数据包中的校验和字段不一致,则说明数据包在传输过程中出现了错误。 以下是一个计算IPv4数据包校验和的Python代码示例: ```python import struct def calculate_checksum(data): # 如果数据长度为奇数,则在末尾添加一个0 if len(data) % 2 == 1: data += b'\x00' # 将数据按16位字进行分组,并将每组字两两相加 words = struct.unpack('>' + 'H' * (len(data) // 2), data) checksum = sum(words) # 将相加得到的结果的高16位和低16位相加,直到结果的高16位为0 while checksum >> 16: checksum = (checksum & 0xffff) + (checksum >> 16) # 将结果取反得到最终的校验和 checksum = ~checksum & 0xffff return checksum # 示例数据包 data = b'\x45\x00\x00\x28\x00\x00\x40\x00\x40\x11\xb8\x1f\xc0\xa8\x01\x01\xc0\xa8\x01\xc7\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # 计算校验和并输出结果 checksum = calculate_checksum(data) print(hex(checksum)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值