0
votes

I'm attempting to generate a packet from scratch with Layer 2, 3, and 4 components (namely Ethernet, IP, and UDP). My socket is configured to use SOCK_RAW as the type and IPPROTO_RAW as the protocol, so that my program can be used to send different protocols at a later date. I've strictly abided by the sendto(2) man page (https://linux.die.net/man/2/sendto), however, I still seem to be having troubles transmitting a packet over local host. The error returned by my program is 22, or EINVAL, indicating that I've passed an incorrect argument.

I've already used Sockets sendto() returning EINVAL and Socket programming: sendto always fails with errno 22 (EINVAL) in attempt to resolve my problem. I've even switched the socket to use SOCK_DGRAM as the type and IPPROTO_UDP as the protocol to see if it was something to do with the socket (though I don't believe this would have prompted an incorrect argument response).

My code is as follows:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <errno.h>

#define BUFFER 1024

int main(int argc, char *argv[]) {

        /* Socket Creation */
    int sockfd;

    if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
            perror("Socket");
            exit(EXIT_FAILURE);
    }

    // This will hold all of the packet's contents
    char sendbuf[BUFFER];


    /* Address Stuff */

    // Specify Address
    in_addr_t address = inet_addr("127.0.0.1");

    // Specifying Address for Sendto()
    struct sockaddr_in sendto_addr;
    memset(&sendto_addr, 0, sizeof(sendto_addr));
    sendto_addr.sin_family = AF_INET;
    sendto_addr.sin_port = htons(9623);  // Make sure the port isn't contested
    sendto_addr.sin_addr.s_addr = address;

    // Size of whole packet
    size_t total_len = 0;


    /* LAYER 2 */
    // Ethernet Header Configuration
    struct ether_header *ether = (struct ether_header *)sendbuf;
    int i;
    for (i = 0; i < 6; ++i) {
        ether -> ether_dhost[i] = 0x00; // Temporary data fill
        ether -> ether_shost[i] = 0x00; // Temporary data fill
    }
    ether -> ether_type = ETHERTYPE_IP;

    total_len += sizeof(struct ether_header);


    /* LAYER 3 */
    // IP Header Configuration
    struct ip *ip = (struct ip *)(sendbuf + sizeof(struct ether_header));

    ip -> ip_hl = 5;
    ip -> ip_v = 4;
    ip -> ip_tos = 0;
    ip -> ip_p = 17;
    ip -> ip_ttl = 255;
    ip -> ip_src.s_addr = address;
    ip -> ip_dst.s_addr = address;  

    total_len += sizeof(struct ip); 


    /* LAYER 4 */
    // UDP Header Configuration
    struct udphdr *udp = (struct udphdr *)(sendbuf + sizeof(struct ether_header) + \
                                           sizeof(struct ip));

    udp -> source = 123; // Gibberish to fill in later
    udp -> dest = 321;   // Gibberish to fill in later
    udp -> check = 0;

    total_len += sizeof(struct udphdr);


    /* Giberrish Packet Data */
    sendbuf[total_len++] = 0x00;
    sendbuf[total_len++] = 0x00;
    sendbuf[total_len++] = 0x00;
    sendbuf[total_len++] = 0x00;


    /* Fill in Rest of Headers */
    udp -> len = htons(total_len - sizeof(struct ether_header) - sizeof(struct ip));
    ip -> ip_len = htons(total_len - sizeof(struct ether_header));


    /* Send Packet */  // ERROR OCCURS HERE
    printf("Sockfd is %d\n", sockfd);
    printf("Total length is %d\n", total_len);
    if (sendto(sockfd, sendbuf, total_len, 0, (const struct sockaddr*)&sendto_addr, \
        sizeof(sendto_addr)) < 0) {
            printf("Error sending packet: Error %d.\n", errno);
            perror("sendto Error");
            exit(EXIT_FAILURE);
    } 

    close(sockfd);

}

The precise console message states:

Sockfd is 3
Total length is 46
Error sending packet: Error 22.
sendto Error: Invalid argument

1
What OS / kernel are you running? Also #define BUFFER 65535 and char sendbuf[BUFFER]; - that's 65 KiB of memory, that's a lot. Usually OSes don't allow more then 4Kb to be allocated on stack.KamilCuk
@KamilCuk OS: Red Hat Enterprise Linux v. 7.6 // Kernel: 3.10.0-957.12.1.el7.x86_64 // I've lowered it to 1024, thank you for the advice!NolanRudolph

1 Answers

0
votes

Eureka! It was actually this line:

if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
        perror("Socket");
        exit(EXIT_FAILURE);
}

Which should have been

if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
        perror("Socket");
        exit(EXIT_FAILURE);
}

Why this fixed the problem? Great question, would love to see someone's response on the subject :P