2

我有一本书名为 .NET 中的网络编程,其中包含以下代码示例,用于在网络堆栈上嗅探 IP 数据包。我已经从书中复制了代码示例 WORD-FOR-WORD 所以请原谅缺乏文体约定等。

List<string> packets = new List<string>();

public void Run()
{
    int len_receive_buf = 4096;
    int len_send_buf = 4096;
    byte[] receive_buf = new byte[len_receive_buf];
    byte[] send_buf = new byte[len_send_buf];
    int cout_receive_bytes;
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
    socket.Blocking = false;
    IPHostEntry IPHost = Dns.GetHostByName(Dns.GetHostName());
    socket.Bind(new IPEndPoint(IPAddress.Parse(IPHost.AddressList[0].ToString()), 0));
    socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1);
    byte[] IN = new byte[4] { 1, 0, 0, 0 };
    byte[] OUT = new byte[4];
    int SIO_RCVALL = unchecked((int)0x98000001);
    int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT);
    while(true)
    {
        IAsyncResult ar = socket.BeginReceive(receive_buf, 0, len_receive_buf, SocketFlags.None, null, this);
        cout_receive_bytes = socket.EndReceive(ar);
        Receive(receive_buf, cout_receive_bytes);
    }
}

public void Receive(byte[] buf, int len)
{
    if(buf[9] == 6)
    {
        packets.Add(Encoding.ASCII.GetString(buf).Replace("\0", " "));
    }
}

我第一次测试这个是几年前(甚至在 Vista 出现之前),我使用的机器是一个 32 位 Windows XP Professional 平台,带有一个在 IPv4 上运行的 NIC。

我现在正在尝试在 64 位 Windows 7 平台上使用运行 IPv6 的 NIC 进行测试,但它无法正常工作。我假设这与 IPv6 有关。谁能建议我如何有效地解决这个问题?

编辑:这是我尝试运行时遇到的异常......

在此处输入图像描述

4

1 回答 1

6

IPv4IPv6之间的标头有很大不同。

所以检查:

if(buf[9] == 6)

它检查数据包是否是 TCP for IPv4 正在查询 IPv6 数据包的源地址字段的一部分。对于 IPv6,它应该检查偏移量 6* 处的“Next Header”。当然,现在您还必须先检查 IP 版本才能知道是检查偏移量 6 还是偏移量 9。


对于异常消息,您可能没有以管理员身份运行,您需要监听原始套接字(本机文档,但仍然适用):

要使用SOCK_RAW类型的套接字需要管理权限。运行使用原始套接字的 Winsock 应用程序的用户必须是本地计算机上管理员组的成员,否则原始套接字调用将失败,错误代码为WSAEACCES. 在 Windows Vista 和更高版本上,对原始套接字的访问是在创建套接字时强制执行的。在早期版本的 Windows 中,对原始套接字的访问是在其他套接字操作期间强制执行的。


(*) 当然,在您发现它是 TCP 数据包之前,可能需要处理多个 IPv6 标头。

于 2012-09-10T09:17:11.730 回答