Windows IPv6 raw сокеты - почему я не вижу входящих пакетов? - PullRequest
0 голосов
/ 07 сентября 2018

Я пишу программу на C ++ для Windows, которая создает необработанный сокет, привязывает его к интерфейсу IPv6 и пытается получить пакеты IPv6. По какой-то причине recv() не возвращает никаких пакетов, хотя я уверен, что пакеты IPv6 получены на интерфейсе (я проверил, используя 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.

Кроме того, вот используемый мной make-файл:

# 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

EDIT:

Следуя комментариям ниже, мне удалось увидеть трафик IPv6, заменив строку SOCKET fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IPV6) на SOCKET fd = socket(AF_INET6, SOCK_RAW, IPPROTO_IP). Однако пакеты, которые я получаю, не имеют заголовка IPv6, что является ожидаемым поведением (см. комментарий Реми Лебо ниже ). Итак, мой вопрос: как мне узнать протокол полезной нагрузки, которую я получаю? Обычно протокол полезной нагрузки упоминается в заголовке IPv6, но, поскольку у меня его нет, как я могу узнать / угадать его?

...