代码之家  ›  专栏  ›  技术社区  ›  seladb

Windows IPv6原始套接字-为什么我看不到传入的数据包?

  •  2
  • seladb  · 技术社区  · 6 年前

    我正在编写一个Windows上的C++程序,它创建一个原始套接字,将它绑定到一个IPv6接口,并尝试刷新IPv6数据包。不知为什么 recv() 在接口上收到(我使用Wireshark进行了验证)。

    这是我写的代码:

    #include <stdio.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <string>
    #include "IpUtils.h"
    
    #define SIO_RCVALL  0x98000001
    #define RAW_SOCKET_BUFFER_LEN 65536
    
    int main()
    {
        int timeout = 10; // 10 seconds
        std::string ipv6Addr = "my IPv6 address...";
        int numOfPackets = 1; // try to read just one packet
    
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2,2), &wsaData);
    
        SOCKET fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IPV6);
        if (fd < 0)
        {
            printf("error in socket creation\n");
            return 1;
        }
        else
            printf("socket creation succeeded\n");
    
        struct sockaddr_in6 localAddrIPv6;
        localAddrIPv6.sin6_family = AF_INET6;
        inet_pton(AF_INET6, ipv6Addr.c_str(), &localAddrIPv6.sin6_addr.s6_addr);
        localAddrIPv6.sin6_port = 0; // Any local port will do
        localAddrIPv6.sin6_scope_id = 0;
    
        if (bind(fd, (struct sockaddr *)&localAddrIPv6, sizeof(localAddrIPv6)) < 0)
        {
            printf("error in bind, error code was %d\n", WSAGetLastError());
            closesocket(fd);
            return 1;
        }
        else
            printf("bind succeeded\n");
    
        int n = 1;
        DWORD dwBytesRet;
        if (WSAIoctl(fd, SIO_RCVALL, &n, sizeof(n), NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR)
        {
            printf("Call to WSAIotcl(%ul) failed with error code %d\n", SIO_RCVALL, WSAGetLastError());
            closesocket(fd);
            return 1;
        }
        else
            printf("call to WSAIotcl succeeded\n");
    
        DWORD timeoutVal = timeout * 1000;
        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeoutVal, sizeof(timeoutVal));
    
        for (int i = 0; i < numOfPackets; i++)
        {
            char* buffer = new char[RAW_SOCKET_BUFFER_LEN];
            memset(buffer, 0, RAW_SOCKET_BUFFER_LEN);
    
            printf("start recv for packet #%d\n", i);
            int bufferLen = recv(fd, buffer, RAW_SOCKET_BUFFER_LEN, 0);
            if (bufferLen < 0)
            {
                printf("recv failed with an error code %d\n", WSAGetLastError());
                closesocket(fd);
                delete [] buffer;
                return 1;
            }
            else
            {
                printf("Got a packet with len %d\n", bufferLen);
            }
    
            delete [] buffer;
        }
    
        return 0;
    }
    

    IpUtils.h 包含的Windows实现 inet_pton() 如[此处][1]所述。

    我使用的编译器是MinGW/MinGW-w64。

    另外,下面是我正在使用的makefile:

    # All Target
    all:
        g++.exe -c -o IpUtils.o IpUtils.cpp
        g++.exe -c -o main.o main.cpp
        g++.exe -o test.exe main.o IpUtils.o -lws2_32
    
    # Clean Target
    clean:
        del main.o
        del IpUtils.o
        del test.exe
    

    运行程序后得到的输出是:

    socket creation succeeded
    bind succeeded
    call to WSAIotcl succeeded
    start recv for packet #0
    recv failed with an error code 10060 <== WSAETIMEDOUT which means timeout expired
    

    编辑:

    根据下面的评论,我设法通过替换行来查看IPv6流量 SOCKET fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IPV6) 具有 SOCKET fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IP) Remy Lebeau's comment below ). 所以我现在的问题是如何知道我得到的有效载荷的协议?通常IPv6头中会提到有效负载协议,但是由于我没有它,我如何知道/猜测它?

    0 回复  |  直到 6 年前