• 承载于以太网帧之上的数据包的解析——ARP、IPv4、IPv6


    承接上一博文而来,继续解析网络数据包,对于承载在以太网上的三种协议进行了解析,主要是分为依据RFC定义的标准先解析头部数据,然后得到有效载荷,即为协议包括的实体数据,更上层进行进一步处理。

    一、ARP协议

    该协议作为局域网IP地址和MAC地址映射的重要协议,与DNS将域名与IP地址进行映射有异曲同工之妙。当以太网的类型字段为 0x0806时即为ARP协议数据包。定义例如以下图:


    硬件类型即为以太网的代码。ARP支持的协议类型为IP(0x0800),硬件地址长度即MAC地址长度为6,协议地址长度为IP地址长度为4,OP字段为当前数据报的类型,0x0001表示请求包,0x0002表示应答包。这些就构成了ARP数据报头,一共8个Byte。

    随后的20个Byte分别如上图所看到的,用来进行MAC地址和IP地址映射。

    解析例如以下:

        /// <summary>
        /// Define the ARP packet header by RFC826
        /// </summary>
        public class ARPPacketHeader : INetworkLayerHeader
        {
            public ushort HardwareType = 0;         //2 Bytes 硬件类型
            public ushort ProtocalType = 0;         //2 Bytes 协议类型
            public byte HardwareAddressLength = 6;  //1 Byte  硬件地址长度(即MAC地址长度为6)
            public byte ProtocolAddressLength = 4;  //1 Byte  协议地址长度(即IP地址长度为4)
            public ushort OP = 0;                   //2 Byte  ARP包类型(0x0001:请求包  0x0002:应答包)
        }
    /// <summary>
        /// Parse the ARP packet
        /// </summary>
        public class ARPPacket : INetworkLayerPacket
        {
            private byte[] RawPacket;
    
            public ARPPacketHeader Header;
            public string SenderMAC;
            public string SenderIP;
            public string ReceiverMAC;
            public string ReceiverIP;
            
            public ARPPacket(byte[] rawArpPacket)
            {
                SenderMAC = Util.JoinByteArr(Util.SubByteArr(rawArpPacket, 8, 6), "-");
                SenderIP = Util.JoinByteArr(Util.SubByteArr(rawArpPacket, 14, 4), ".", "d");
                ReceiverMAC = Util.JoinByteArr(Util.SubByteArr(rawArpPacket, 18, 6), "-");
                ReceiverIP = Util.JoinByteArr(Util.SubByteArr(rawArpPacket, 24, 4), ".", "d");
    
                RawPacket = rawArpPacket;
            }
    
            public INetworkLayerHeader getHeader()
            {
                Header = new ARPPacketHeader();
                Header.HardwareType = (ushort)((ushort)(RawPacket[0] << 8) + (ushort)RawPacket[1]);
                Header.ProtocalType = (ushort)((ushort)(RawPacket[2] << 8) + (ushort)RawPacket[3]);
                Header.HardwareAddressLength = (byte)RawPacket[4];
                Header.ProtocolAddressLength = (byte)RawPacket[5];
                Header.OP = (ushort)((ushort)(RawPacket[6] << 8) + (ushort)RawPacket[7]);
                return Header;
            }
    
            public byte[] getBody()
            {
                return Util.SubByteArr(RawPacket, 8);
            }
        }

    二、IPv4协议

    解析过程与上述类似,能够进行类比。作为最广泛的网络层协议,具体结构就不赘述。直接看结构图:


    解析步骤例如以下:

        /// <summary>
        /// Define the IPv4 packet header by RFC791
        /// </summary>
        public class IPv4PacketHeader : INetworkLayerHeader
        {
            public byte Version = 4;            //3 bits  版本
            public byte Length = 0;             //5 bits  头部长度
            public byte Tos = 0;                //1 Byte  服务类型
            public ushort DatagramLength = 0;   //2 Bytes 数据包长度
    
            public ushort Identification = 0;   //2 Bytes 标识
            public byte Mark = 0;               //3 bits  标志
            public ushort Offset = 0;           //13 bits 片偏移
    
            public byte TTL = 0;                //1 Byte  数据包寿命
            public byte UpperProtocal = 0;      //1 Byte  上层协议
            public ushort HeaderChecksum = 0;   //2 Byte  头部检查和
            
            public string SrcIP = "";              //4 Bytes  源IP地址
    
            public string DstIP = "";              //4 Bytes  目的IP地址
        }
        /// <summary>
        /// Parse the IPv4 packet
        /// </summary>
        public class IPv4Packet : INetworkLayerPacket
        {
            private byte[] RawPacket;
    
            public IPv4PacketHeader Header;
            public byte[] Body;
    
            public IPv4Packet(byte[] rawPacket)
            {
                RawPacket = rawPacket;
            }
    
            public INetworkLayerHeader getHeader()
            {
                Header = new IPv4PacketHeader();
                Header.Length = (byte)(RawPacket[0] & 0x1f);
                Header.Tos = RawPacket[1];
                Header.DatagramLength = (ushort)((ushort)(RawPacket[2] << 8) + (ushort)RawPacket[3]);
                Header.Identification = (ushort)((ushort)(RawPacket[4] << 8) + (ushort)RawPacket[5]);
                Header.Mark = (byte)(RawPacket[6] >> 5);
                Header.Offset = (ushort)((ushort)((RawPacket[6] & 0x1f) << 8) + (ushort)RawPacket[7]);
                Header.TTL = RawPacket[8];
                Header.UpperProtocal = RawPacket[9];
                Header.HeaderChecksum = (ushort)((ushort)(RawPacket[10] << 8) + (ushort)RawPacket[11]);
    
                Header.SrcIP = Util.JoinByteArr(Util.SubByteArr(RawPacket, 12, 4), ".", "d");
                Header.DstIP = Util.JoinByteArr(Util.SubByteArr(RawPacket, 16, 4), ".", "d");
                return Header;
            }
    
            public byte[] getBody()
            {
                Body = Util.SubByteArr(RawPacket, 20);
                return Body;
            }
        }

    三、IPv6协议

    IPv6是用来替代IPv4以解决地址空间不足的问题而发展起来的,同一时候改协议在IPv4的基础上也做了非常大其它方面的修改,如不同意在中间路由器上进行分片操作等。眼下应用范围尽管难以达到代替IPv4的程度,可是提供了较大优势。下图为其数据报结构:


    解析步骤例如以下:

        /// <summary>
        /// Define the IPv6 packet header by RFC 2460
        /// </summary>
        public class IPv6PacketHeader : INetworkLayerHeader
        {
            public byte Version = 6;            //3 bits   版本
            public byte Tos = 0;                //1 Byte   流量(服务)类型
            public uint FlowTag = 0;            //21 bits  流标签
    
            public ushort AvaiLoad = 0;         //2 Bytes  有效载荷长度
            public byte NextHeader = 0;         //1 Byte   下个首部(与IPv4中的协议字段值同样)
            public byte HopLimit = 0;           //1 Byte   跳数限制
            
            public string SrcIP = "";           //16 Bytes 源IPv6地址
    
            public string DstIP = "";           //16 Bytes 目的IPv6地址
        }
        /// <summary>
        /// Parse the IPv6 packet
        /// </summary>
        public class IPv6Packet : INetworkLayerPacket
        {
            private byte[] RawPacket;
    
            public IPv6PacketHeader Header;
            public byte[] Body;
    
            public IPv6Packet(byte[] rawPacket)
            {
                RawPacket = rawPacket;
            }
    
            public INetworkLayerHeader getHeader()
            {
                Header = new IPv6PacketHeader();
                Header.Tos = (byte)((RawPacket[0] & 0x1fu) << 3 + RawPacket[1] >> 5);
                Header.FlowTag = (uint)((RawPacket[1] & 0x1fu) << 16 + RawPacket[2] << 8 + RawPacket[3]);
                Header.AvaiLoad = (ushort)((ushort)(RawPacket[4] << 8) + (ushort)RawPacket[5]);
                Header.NextHeader = RawPacket[6];
                Header.HopLimit = RawPacket[7];
    
                Header.SrcIP = Util.JoinByteArr(Util.SubByteArr(RawPacket, 8, 16), ":", "X2", 2);
                Header.DstIP = Util.JoinByteArr(Util.SubByteArr(RawPacket, 24, 16), ":", "X2", 2);
                return Header;
            }
    
            public Byte[] getBody()
            {
                Body = Util.SubByteArr(RawPacket, 40);
                return Body;
            }
        }

    通过对这些协议的亲自剖析,能够更加对网络传输有了更深的理解,同一时候相应用层的应用开发也有非常好的指导作用。


  • 相关阅读:
    Redis 集群方案
    Redis集群搭建
    Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS
    为什么分布式一定要有Redis?
    如何准备Java初级和高级的技术面试
    SpringBoot自动配置原理
    高德地图-- 云图管理台
    GeoJSON格式规范说明
    webGis概念
    npm压缩js文件
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4318028.html
Copyright © 2020-2023  润新知