1

I am working on writing a ping CLI program for linux and I have been getting errno 22: invalid argument in the sendto() function. I don't understand why, all the arguments seem to be correct.

Here is where I call the function:

    // send echo request
    bytesSent = sendto(socketFD,                                                        // socket file descriptor
                      (char*)&packet, PacketSize,                                       // packet and size
                      0,                                                                // flags
                      (sockaddr*)DestinationAddr, (socklen_t)sizeof(DestinationAddr));  // destination address and size

'packet' looks like this: (I call initializePacket() in the function where I call sendto())

struct PacketData {
    icmphdr header;
    char message[PacketSize - sizeof(header)];      // want total size to be 64 bytes
};

PacketData initializePacket(int &transmitted) {
    PacketData packet = {};

    packet.header.type = ICMP_ECHO;                 // set ICMP type to Echo
    packet.header.un.echo.id = getpid() & 0xFFFF;   // set id (ICMP field is 16 bits)
    packet.header.checksum = 0;                     // fixed checksum because data is unchanging
    packet.header.un.echo.sequence = transmitted++;

    // fill up message
    memset(&packet.message, '0', sizeof(packet.message));
    packet.message[PacketSize - sizeof(packet.header) - 1] = '\0';

    return packet;
}

'DestinationAddr' is this:

    // variables needed to store IP Address
    addrinfo* result;
    sockaddr_in* DestinationAddr;
    char ipString[INET_ADDRSTRLEN];

    // get IP Address and store in result (passed by reference)
    if (getIPAddress(argv[1], result) != 0) {
        std::cout << "Invalid IP Address. Terminating ...\n";
        exit(EXIT_FAILURE);
    }
    else {
        DestinationAddr = (sockaddr_in*)result->ai_addr;                        // get struct from resulting linked list
        void* address;
        address = &DestinationAddr->sin_addr;                                   // store IP Address
        inet_ntop(result->ai_family, address, ipString, sizeof(ipString));      // convert binary IP to string
        std::cout << "IP: " << ipString << std::endl;
    }

And the getIPAddress() function is:

int getIPAddress(char* hostName, addrinfo* &result) {
    addrinfo tempStruct = {0};

    tempStruct.ai_family = AF_INET;         // want IPv4
    tempStruct.ai_socktype = SOCK_DGRAM;    // set socket type to datagram
    tempStruct.ai_flags = AI_PASSIVE;       // fill in IP automatically

    // get and validate IP address
    return (getaddrinfo(hostName, &PortNo, &tempStruct, &result));
}

PortNo is defined as: const char PortNo = '0';

Mustafa
  • 66
  • 7
  • Why are you trying to send an ICMP packet over UDP? – user207421 May 29 '20 at 08:56
  • @user207421 I am doing that because UDP does not require a connection to be established before sending out data and it is best suited when speed is needed, so I thought that would be best. – Mustafa May 30 '20 at 00:15

1 Answers1

0

According to documentation icmp:

A user protocol may receive ICMP packets for all local sockets by opening a raw socket with the protocol IPPROTO_ICMP.

So, try creating your socket like that:

socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)

And, if you encounter EPERM error, then run your program as root.

mar
  • 154
  • 7
  • I orginally did: `socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)` and I tried doing this as well, but it gives the same error. (errno 22) – Mustafa May 30 '20 at 00:17
  • Please read https://stackoverflow.com/a/8190018/13321798. And here is example implementation: https://gist.github.com/kbaribeau/4495181 – mar May 30 '20 at 07:31
  • I was able to find the error. It was because I was calling sizeof() on a pointer - DestinationAddr - I dereferenced it and the invalid argument error was gone. Now, it sends the data successfully (sendto() returns 64) but it does not receive data. The timeout causes it to end and if I remove the timeout, then it just keeps waiting for data. (errno 11 (resource temporarily unavailable) is given) – Mustafa May 31 '20 at 04:50