none
C# 抓取ipv6包的问题 RRS feed

  • 问题

  • using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Net.Sockets;
    using System.Net;
    using System.IO;

    namespace IPv6Packet
    {


    [StructLayout(LayoutKind.Explicit)]
    public struct IPv6Header //IPv6头部定义
    {
    [FieldOffset(0)] //此处定义了字段在此结构当中的绝对位置,以字节为单位
    public uint ipv6_fisrt; //IPv6头部首32位数据
    [FieldOffset(4)]
    public ushort len1; //16位数据长度
    [FieldOffset(6)]
    public byte next; //下一个包类型
    [FieldOffset(7)]
    public byte hopLmt; //跳数限制

    [FieldOffset(8)] /*以下为源地址*********************/
    public short ip_srcaddr1;
    [FieldOffset(10)]
    public short ip_srcaddr2;
    [FieldOffset(12)]
    public short ip_srcaddr3;
    [FieldOffset(14)]
    public short ip_srcaddr4;
    [FieldOffset(16)]
    public short ip_srcaddr5;
    [FieldOffset(18)]
    public short ip_srcaddr6;
    [FieldOffset(20)]
    public short ip_srcaddr7;
    [FieldOffset(22)]
    public short ip_srcaddr8;

    [FieldOffset(24)] /*以下为目标地址*********************/
    public short ip_destaddr1;
    [FieldOffset(26)]
    public short ip_destaddr2;
    [FieldOffset(28)]
    public short ip_destaddr3;
    [FieldOffset(30)]
    public short ip_destaddr4;
    [FieldOffset(32)]
    public short ip_destaddr5;
    [FieldOffset(34)]
    public short ip_destaddr6;
    [FieldOffset(36)]
    public short ip_destaddr7;
    [FieldOffset(38)]
    public short ip_destaddr8;
    }

    class PacketArrivedEventArgs : EventArgs //有数据包到达时触发的事件
    {
    public uint HeaderLength = 0;
    public string Protocol = String.Empty;
    public string IPVersion = String.Empty;
    public string OriginationAddress = String.Empty;
    public string OriginationPort = String.Empty;
    public string DestinationAddress = String.Empty;
    public string DestinationPort = String.Empty;
    public uint PacketLength = 0;
    public uint MessageLength = 0;
    public byte[] ReceiveBuffer = null;
    public byte[] IPHeaderBuffer = null;
    public byte[] MessageBuffer = null;

    public PacketArrivedEventArgs()
    {
    }
    }

    class RawSocket
    {
    private bool error_occurred; //套接字在接收包时是否产生错误
    private Socket socket = null; //声明套接字
    public bool keepRunning; //是否继续进行
    private static int len_receive_buf =8192; //得到的数据流的长度
    public byte[] receive_buf_bytes; //收到的字节
    const int SIO_RCVALL = unchecked((int)0x98000001); //监听所有的数据包

    public RawSocket() //构造函数
    {
    this.error_occurred = false;
    this.receive_buf_bytes = new byte[len_receive_buf];
    this.keepRunning = true;
    }

    public bool CreateAndBindSocket(string ip) //建立并绑定套接字
    {
    try
    {
    this.socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Raw, ProtocolType.IP);
    socket.Blocking = false; //置socket非阻塞状态
    socket.Bind(new IPEndPoint(IPAddress.Parse(ip), 0)); //绑定套接字

    if (this.SetSocketOption() == false) //设置socket状态
    this.error_occurred = true;

    return true;
    }
    catch (Exception e)
    {
    return false;
    }
    }

     

    public bool ErrorOccurred()
    {
    return this.error_occurred;
    }

    //开始监听
    public void Run()
    {
    IAsyncResult ar = socket.BeginReceive(receive_buf_bytes, 0, len_receive_buf, SocketFlags.None, new AsyncCallback(this.CallReceive), this);
    }

    //数据包到达时的回调函数
    private void CallReceive(IAsyncResult ar)
    {
    int received_bytes;
    received_bytes = socket.EndReceive(ar);

    if (received_bytes > 0)
    {
    this.Receive(receive_buf_bytes, received_bytes);
    socket.BeginReceive(receive_buf_bytes, 0, len_receive_buf, SocketFlags.None, new AsyncCallback(this.CallReceive), this);
    }

    if (this.keepRunning)
    this.Run();
    }


    unsafe private void Receive(byte[] buf, int len)
    {

    uint trafficClass = 0;
    byte version = 0;
    uint flowLabel = 0;
    ushort msgLen = 0;
    byte nextHeader = 0;
    byte hop = 0;
    ushort srcport = 0;
    ushort dstport = 0;
    string protocol;
    PacketArrivedEventArgs e = new PacketArrivedEventArgs();

    fixed (byte* fixed_buf = buf)
    {
    IPv6Header* head = (IPv6Header*)fixed_buf;

    byte[] ipv6_head = new byte[4];
    ipv6_head = System.BitConverter.GetBytes(head->ipv6_fisrt);

    version = (byte)((ipv6_head[0] & 0xf0) >> 4);

    trafficClass = (uint)(((ipv6_head[0] & 0x0F) << 8) + ((ipv6_head[1] & 0xF0) >> 4));

    ipv6_head[0] = 0;
    ipv6_head[1] = (byte)(ipv6_head[1] & 0x0F);
    flowLabel = (uint)System.BitConverter.ToUInt32(ipv6_head, 0);
    msgLen = head->len1;
    nextHeader = head->next;
    hop = head->hopLmt;
    srcport = *(ushort*)&fixed_buf[40];
    dstport = *(ushort*)&fixed_buf[42];

    switch (nextHeader)
    {
    case 58: protocol = "ICMPv6"; break;
    case 2: protocol = "IGMP"; break;
    case 6: protocol = "TCP"; break;
    case 17: protocol = "UDP"; break;
    default: protocol = "UNKNOWN"; break;
    }

    string srcaddr = "";
    string dstaddr = "";

    srcaddr = Convert.ToString(head->ip_srcaddr1, 16) + ":" + Convert.ToString(head->ip_srcaddr2, 16) + ":" + Convert.ToString(head->ip_srcaddr3, 16) + ":"
    + Convert.ToString(head->ip_srcaddr4, 16) + ":" + Convert.ToString(head->ip_srcaddr5, 16) + ":" + Convert.ToString(head->ip_srcaddr6, 16) + ":" +
    Convert.ToString(head->ip_srcaddr7, 16) + ":" + Convert.ToString(head->ip_srcaddr8, 16);
    dstaddr = Convert.ToString(head->ip_destaddr1, 16) + ":" + Convert.ToString(head->ip_destaddr2, 16) + ":" + Convert.ToString(head->ip_destaddr3, 16) + ":" +
    Convert.ToString(head->ip_destaddr4, 16) + ":" + Convert.ToString(head->ip_destaddr5, 16) + ":" + Convert.ToString(head->ip_destaddr6, 16) + ":" +
    Convert.ToString(head->ip_destaddr7, 16) + ":" + Convert.ToString(head->ip_destaddr8, 16);

    Console.WriteLine("IPv6Packet:\n" + "协议版本:" + version.ToString() + "\n" + "业务等级:" + Convert.ToString(trafficClass, 16) + "\n"
    + "流标记:" + Convert.ToString(flowLabel, 16) + "\n" + "净荷长度:" + msgLen.ToString() + "\n"
    + "下一个头:" + protocol + "\n" + "跳数限制:" + hop.ToString() + "\n" + "源地址:" + srcaddr + "\n"
    + "目标地址:" + dstaddr + "\n" + "源端口:" + srcport + "\n" + "目标端口:" + dstport + "\n");
    }
    }


    public void Shutdown()
    {
    if (socket != null)
    {
    socket.Shutdown(SocketShutdown.Both);
    socket.Close();
    }
    }

     

    private bool SetSocketOption() //设置raw socket
    {
    bool ret_value = true;
    try
    {
    socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HeaderIncluded, 1);
    byte[] IN = new byte[4] { 1, 0, 0, 0 };
    byte[] OUT = new byte[4];

    //低级别操作模式,接受所有的数据包,这一步是关键,必须把socket设成raw和IP Level才可用SIO_RCVALL
    int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT);
    ret_code = OUT[0] + OUT[1] + OUT[2] + OUT[3];

    if (ret_code != 0)
    ret_value = false;
    }
    catch (Exception excp)
    {
    ret_value = false;
    }

    return ret_value;
    }
    }
    }

    其中分析ipv6报文可能有些不对,暂时不关心。我从receive 中得到的buf 只是ipv6报文后的协议报文,并不是ipv6的报文头!!!请问如何能获取ipv6的报文头!

    2011年5月28日 7:06

全部回复

  • public bool CreateAndBindSocket(string ip) //建立并绑定套接字
    {
    try
    {
    this.socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Raw, ProtocolType.IP);
    socket.Blocking = false; //置socket非阻塞状态
    socket.Bind(new IPEndPoint(IPAddress.Parse(ip), 0)); //绑定套接字

    if (this.SetSocketOption() == false) //设置socket状态
    this.error_occurred = true;

    return true;
    }
    catch (Exception e)
    {
    return false;
    }
    }

    private bool SetSocketOption() //设置raw socket
    {
    bool ret_value = true;
    try
    {
    socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HeaderIncluded, 1);

    byte[] IN = new byte[4] { 1, 0, 0, 0};
    byte[] OUT = new byte[4];

    //低级别操作模式,接受所有的数据包,这一步是关键,必须把socket设成raw和IP Level才可用SIO_RCVALL
    int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT);
    ret_code = OUT[0] + OUT[1] + OUT[2] + OUT[3];

    if (ret_code != 0)
    ret_value = false;
    }
    catch (Exception excp)
    {
    ret_value = false;
    }

    return ret_value;
    }
    }

    这两个设置完以后,只能抓到Ipv6的 协议报文,ipv6的报头抓不到。我猜可能是socket默认为 ipv6封装在ipv4里,所以只抓取协议报文。也就是采用了隧道技术,如何才能使socket不采用隧道技术,直接获取ipv6报头而不是协议报文。
    2011年5月28日 9:37
  • 我们正在对你的问题进行研究, 一旦有结果会立即回复. 谢谢.


    Leo Liu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年6月1日 5:02
    版主