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
#define BUFFER 65535
andchar 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