winsock2: RAW SOCKET recvfrom () возвращает ошибку 10022 (недопустимый аргумент) - PullRequest
1 голос
/ 09 мая 2020

Я пытаюсь обработать входящие сетевые пакеты с RAW SOCKET в Windows 10.

Когда я вызываю функцию recvfrom(), она возвращает -1 значение. WSAGetLastError - 10022.

Страница Microsoft Docs дает мне следующее описание:

WSAEINVAL: 10022
Недействительный аргумент.
Был указан недопустимый аргумент (например, , указав недопустимый уровень для функции setsockopt). В некоторых случаях это также относится к текущему состоянию сокета - например, вызов accept для сокета, который не прослушивает.

Я пытался использовать setsockopt() для установки IP_HDRINCL в 1, но он возвращает ту же ошибку, когда я вызываю recvfrom().

Мой исходный код:

#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h"


int main(){
    SOCKET s;
    char* buff = malloc(256);
    int optval = 1;
    struct sockaddr_in adr;
    int adr_length = sizeof(adr);
    int i;
    int rcv_len;
    WSADATA wsa;

    memset(buff, 0, 256);

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        printf("Error in WSAStartup: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    if(s == SOCKET_ERROR){
        printf("Error in socket creation: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == -1){
        printf("Error in setsockopt(): %d\n", WSAGetLastError());
        getch();
        closesocket(s);
        return 0;
    }

    while(1){
        rcv_len = recvfrom(s, buff, 256, 0, (struct sockaddr*)&adr, &adr_length);

        if(rcv_len == -1){
            printf("Error in recvfrom(): %d\n", WSAGetLastError());
            getch();
            break;
        }

        for(i = 0; i < 256; i ++){
            printf("%c", *(buff + i));
        }
    }

    closesocket(s);

    return 1;
}

Возврат:

Error in recvfrom(): 10022

1 Ответ

2 голосов
/ 10 мая 2020

Я решил проблему.

Что не хватало:

  1. Включите РОЗЕТКУ с помощью bind(), используя IP-адрес интерфейса, с которым вы работаете
  2. Установите opt SO_RCVALL в 1 с помощью WSAIoctl()

Итак, теперь код работает с этим источником:

#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h"

int main(){
    SOCKET s;
    unsigned char* buff = malloc(32768);
    int optval = 1;
    struct sockaddr_in adr;
    struct sockaddr_in sadr;
    int adr_length = 0;
    int i;
    int in;
    int rcv_len;
    WSADATA wsa;

    memset(buff, 0, 32768);

    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        printf("Error in WSAStartup: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(s == SOCKET_ERROR){
        printf("Error in socket creation: %d\n", WSAGetLastError());
        getch();
        return 0;
    }

    sadr.sin_family = AF_INET;
    sadr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sadr.sin_port = htons(0);

    bind(s, (struct sockaddr*)&sadr, sizeof(sadr));

    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == -1){
        printf("Error in setsockopt(): %d\n", WSAGetLastError());
        getch();
        closesocket(s);
        return 0;
    }

    optval = 1;
    WSAIoctl(s, SIO_RCVALL, &optval, sizeof(optval), 0, 0, (LPDWORD) &in, 0, 0);

    while(1){
        adr_length = sizeof(adr);
        rcv_len = recvfrom(s, buff, 32768, 0, (struct sockaddr*)&adr, &adr_length);

        if(rcv_len == -1){
            printf("Error in recvfrom(): %d\n", WSAGetLastError());
            getch();
            break;
        }

        for(i = 0; i < rcv_len; i ++){
            printf("%d ", *(buff + i));
        }
    }

    closesocket(s);

    return 1;
}

Всем спасибо!

...