zoukankan      html  css  js  c++  java
  • ip协议栈

    ip

    struct iphdr {
    #if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
                version:4;
    #elif defined (__BIG_ENDIAN_BITFIELD)   //网络字节序
        __u8    version:4,
                ihl:4;
    #else
    #error  "Please fix <asm/byteorder.h>"
    #endif
        __u8    tos;
        __be16  tot_len;
        __be16  id;
        __be16  frag_off;
        __u8    ttl;
        __u8    protocol;
        __sum16 check;
        __be32  saddr;
        __be32  daddr;
    };

    45 00 00 29 38 13 40 00 40 06 7d 60 c0 a8 02 0a c0 a8 02 01
    (1) “45”,其中“4”是IP协议的版本(Version),说明是IP4。“5”是IHL位,表示IP头部的长度,是一个4bit字段,最大就是1111了,IP头部的最大长度就是60字节。而这里为“5”,说明是20字节。IP包头最小长度为20字节(IP头长度包含选项)
    (2) “00”,服务类型(Type of Service)。这个8bit字段由3bit的优先权子字段(现在已经被忽略),4 bit的TOS子字段以及1 bit的未用字段(现在为0)构成.4 bit的TOS子字段包含:最小延时、最大吞吐量、最高可靠性以及最小费用构成,这四个1bit位最多只能有一个为1,本例中都为0,表示是一般服务
    (3) “00 29”,IP数据报文总长,包含头部以及数据,这里表示41字节。这41字节由20字节的IP头部以及21字节的TCP头构成(最后的一个字节为数据)
    (7) “40”这个字节就是TTL(Time To Live)了,表示一个IP数据流的生命周期,用Ping显示的结果,能得到TTL的值。每次IP数据包经过一个路由器的时候TTL就减一,当减到0时,这个数据包就消亡了。这也时Tracert的原理。本例中为“40”,转换为十进制就是64了

    .ttl = IPDEFTTL; 缺省的IP包生存期为64

    (8) “06”,这个字节表示传输层的协议类型

    //Protocols
    #define IPPROTO_IP 0    /* dummy for IP */
    #define IPPROTO_ICMP 1  /* control message protocol */
    #define IPPROTO_IGMP 2  /* internet group management protocol */
    #define IPPROTO_GGP 3   /* gateway^2 (deprecated) */
    #define IPPROTO_TCP 6   /* tcp */
    #define IPPROTO_PUP 12  /* pup */
    #define IPPROTO_UDP 17  /* user datagram protocol */
    #define IPPROTO_IDP 22  /* xns idp */
    #define IPPROTO_ND 77   /* UNOFFICIAL net disk proto */
    #define IPPROTO_RAW 255 /* raw IP packet */
    #define IPPROTO_MAX 256

    (9) “7d 60”这个16bit是头校验和(Header Checksum)
    (10) “c0 a8 02 0a”,这个是源地址
    (11) “c0 a8 02 01”,这个是目标地址

    IP校验和

    /*
        buffer:IP首部的起始地址
        size:IP首部的大小
    */
    SHORT checksum(USHORT* buffer, int size)
    {
        unsigned long cksum = 0;
        while(size>1)
        {
            cksum += ntohs(*buffer++);
            size -= sizeof(USHORT);
        }
        if(size)
        {
            cksum += *(UCHAR*)buffer;
        }
        cksum = (cksum >> 16) + (cksum & 0xffff); 
        cksum += (cksum >> 16); 
    
        return (USHORT)(~cksum);
    }
    • 把校验和字段清零
    • 对每16位进行二进制反码求和,反码求和的意思是先对每16位求和,再将得到的和转为反码

    (cksum >> 16) + (cksum & 0xffff):将高16位与低16位相加
    cksum += (cksum >> 16):第一步相加可能产生进位

    举例

    45 00   00 31
    89 F5   00 00
    6E 06   00 00(校验字段)
    C0 A8   01 0A   ->  192.168.1.10
    C0 A8   04 0C   ->  192.168.4.12
    
    4500 + 0031 + 89F5 + 0000 + 6e06+ 0000 + C0A8 + 010A + C0A8 + 040C = 2 C392
    0002 + C392 = C394
    ~22C7 = 3C6B

    注:校验和计算时需要主机序;计算完的校验和需要转换成网络序

  • 相关阅读:
    nvelocity的Foreach 中使用DataTable数据
    好的博客链接收集
    Uber Shaders
    DOF
    纹理过滤模式中的Bilinear、Trilinear以及Anistropic Filtering
    开通博客了
    代码中的隐式转换问题
    使用C++/CLI封装引用BOOST库的DLL造成的问题
    在Free Radius的PAP认证过程中使用MD5密码
    (转)测试CPU是大端Big endian 还是小端Little Endian的C代码
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709846.html
Copyright © 2011-2022 走看看