IPv4 total length exceeds packet length (64 bytes) on crafted packet - c

GOAL: crafting a packet from zero including ethernet header, ip header, udp header and a seccomp_data structure as data.
PROBLEM: I'm struggling to correctly craft the packet, in fact currently when I sniff the traffic wireshark gives me Expert Info (Error/Protocol): IPv4 total length exceeds packet length (64 bytes) where the resulting length of the packet is 23552. What am I missing?
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 1024
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=ETH_HLEN;
struct ifreq ifr;
size_t if_name_len;
char buf[BUF_SIZE];
struct ether_header *eh = (struct ether_header *) buf;
struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct ether_header) + sizeof(struct iphdr));
unsigned char *data = buf + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0xff, 0x99, 0x88, 0x77, 0x66, 0x55};
// create raw socket to send/receive ethernet frames that transport ip packet
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
memset(&sec_payload,0,sizeof(struct seccomp_data));
data = (char*)malloc(sizeof(struct seccomp_data));
memcpy(data, (const unsigned char *)&sec_payload, sizeof(struct seccomp_data));
int i;
for(i=0;i<sizeof(sec_payload);i++){
buf[tx_len++] = data[i];
printf("%02X ",data[i]);
}
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload);
iph->id = htons(54321);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
memset(&dst_addr,0,sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
printf("tx_len %d\n, tot_len %d\n", tx_len, iph->tot_len);
if (sendto(sockfd, buf, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}

Network byte order (the order in which bytes are typically transmitted on Internet protocols) is big endian, the most significant bytes are transmitted first. In particular, you need to htons() the total length field.

Related

getaddrinfo: Address family for nodename not supported in MacOS

I keep getting this error getaddrinfo failed: Undefined error: 0. I am trying to compile my code on MacOS using the command gcc mac-client-2.c -o client. The program is compiling successfully, but when I run the executable, the error above shows up. I searched google and SO, the closest thing I could find to the problem was this link Undefined reference to getaddrinfo But, this link talks about the issue for windows, not for MacOS.
I am pasting my code as it is below. Could anyone please help.
EDIT: Got a more descriptive error saying getaddrinfo: Address family for nodename not supported
// Client side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h> //Provides declarations for udp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netdb.h>
#include <errno.h>
#define PORT 12345
#define MAXLINE 1024
//standard checksum function
unsigned short csum(unsigned short *ptr, int nbytes)
{
register long sum;
unsigned short oddbyte;
register short answer;
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_char *)&oddbyte) = *(u_char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
answer = (short)~sum;
return (answer);
}
// struct ip
// {
// unsigned char ihl;
// unsigned char version;
// unsigned char tos;
// unsigned short int tot_len;
// unsigned short int id;
// unsigned short int frag_off;
// unsigned char ttl;
// unsigned char protocol;
// unsigned short int check;
// unsigned int saddr;
// unsigned int daddr;
// };
//required for udp
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
// Driver code
int main()
{
int errno;
int sockfd, raw_sock;
char buffer[MAXLINE];
int port;
char *hello = "Client Hello";
char *done = "Client Done";
char source_ip[32];
struct sockaddr_in servaddr;
struct sockaddr_in local_address;
int addr_size = sizeof(local_address);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
if ((raw_sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) //PF_PACKET -- 0 can be replaced with IPPROTO_UDP (gives same outcome)
{
perror("Raw Socket creation failed");
exit(EXIT_FAILURE);
}
setuid(getuid());
//********** Part with getaddrinfo//*********
int stat;
struct addrinfo hints;
struct addrinfo *info, *ptr;
struct sockaddr_in *client_address;
char clientIPstr[16];
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; //put NULL in getaddrinfo
//AI_PASSIVE allows to assign address of local host
//No hardcoding needed
if ((stat = getaddrinfo(NULL, "0", &hints, &info) != 0))
{
perror("getaddrinfo failed");
exit(EXIT_FAILURE);
}
for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
{
if (ptr->ai_family == AF_INET)
{
client_address = (struct sockaddr_in *)ptr->ai_addr;
inet_ntop(AF_INET, &(client_address->sin_addr), clientIPstr, sizeof(clientIPstr));
printf("%s\n", clientIPstr);
int x = bind(sockfd, ptr->ai_addr, ptr->ai_addrlen);
//int y = bind(raw_sock, ptr->ai_addr, ptr->ai_addrlen);
//printf("Bind Status: %d, %d\n", x, y);
break;
}
}
///************///************////*****************
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET; //IPv4
servaddr.sin_port = htons(PORT); //8080
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
int len, n;
//send hello
sendto(sockfd, (const char *)hello, strlen(hello),
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
//fetch the port number and store in local address -- dont forget to convert using ntohs
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size);
port = ntohs(local_address.sin_port);
printf("My Port: %u\n", port);
//receive hello
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
/* ---------------------Packet spoofing code starts here----------------------- */
printf("Creating spoofed packet\n");
char spoof_packet[4096];
char *data, *pseudogram;
int one = 1;
const int *val = &one;
memset(spoof_packet, 0, 4096);
//strcpy(clientIPstr, "127.0.0.1");
struct ip *iph = (struct ip *)spoof_packet;
struct udphdr *udph = (struct udphdr *)(spoof_packet + sizeof(struct ip));
struct pseudo_header psh;
struct sockaddr_in my_sockaddress;
my_sockaddress.sin_addr.s_addr = inet_addr(clientIPstr); //just set this to htonl(INADDR_ANY); instead of 127.0.0.1
//struct sockaddr_in sin;
data = spoof_packet + sizeof(struct ip) + sizeof(struct udphdr);
strcpy(data, "SPOOFED CLIENT DONE");
strcpy(source_ip, clientIPstr);
//IP Header
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(struct ip) + sizeof(struct udphdr) + strlen(data);
iph->ip_id = htonl(54321); //Id of this packet
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_UDP;
iph->ip_sum = 0; //Set to 0 before calculating checksum
iph->ip_src = my_sockaddress.sin_addr; //Spoof the source ip address
iph->ip_dst = servaddr.sin_addr; //value should be of type in_addr
iph->ip_sum = csum((unsigned short *)spoof_packet, iph->ip_len); //ip checksum
//UDP header
udph->uh_sport = local_address.sin_port;
udph->uh_dport = htons(PORT);
udph->uh_ulen = htons(8 + strlen(data)); //header size
udph->uh_sum = 0; //leave checksum 0 now, filled later by pseudo header
/* Stackoverflow - The IPv4 layer generates an IP header when sending a packet unless the IP_HDRINCL socket
option is enabled on the socket. When it is enabled, the packet must contain an IP header.
For receiving the IP header is always included in the packet.*/
if (setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
//UDP checksum using the pseudo header
psh.source_address = inet_addr(source_ip);
psh.dest_address = servaddr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data));
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram, (char *)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), udph, sizeof(struct udphdr) + strlen(data));
udph->uh_sum = csum((unsigned short *)pseudogram, psize);
printf("%s\n", spoof_packet);
printf("Sending spoofed packet.......");
int k;
//send spoofed Done
k = sendto(raw_sock, spoof_packet, iph->ip_len,
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
if (k == -1)
{
printf("Error sending: %i\n", errno);
}
printf("%d\n", k);
fflush(stdout);
/*---------------------------------END------------------------------------------*/
//send Done
// sendto(sockfd, (const char *)done, strlen(done),
// 0, (const struct sockaddr *)&servaddr,
// sizeof(servaddr));
//receive done
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
//close(sockfd);
return 0;
}
/* get ip and port number:
char myIP[16];
struct sockaddr_in local_address;
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size); //get socket info
inet_ntop(AF_INET, &local_address.sin_addr, myIP, sizeof(myIP)); // get IP info
int myPort = ntohs(local_address.sin_port); //get port info
printf("Local ip address: %s\n", myIP);
printf("Local port : %u\n", myPort);
*/
Your struct addrinfo hints; is uninitialized, and has junk in the members you did not explicitly write to. Change it to struct addrinfo hints = { 0 }; or put all the hints in designated initializers rather than assignments after creation of an uninitialized object.
So, I forgot to post back here. I had figured out the solution. Its basically the same as the above post. Just added the line memset(&hints,0,sizeof(hints)) and everything worked perfectly.

Netcat doesn' receive udp crafted packet

GOAL: send a crafted udp packet from 127.0.0.1 pport 8090 to localhost port 8091.
PROBLEM: the code shown below, as far I can see from wireshark, works in fact I can see my packet exactly with the values I chosen. Anyway if on terminal A I execute nc -ulp 8091 -vv and on terminal B I execute the program, nothing happens. I thought that the string "hhhhhhhhhh" should be visible in the output.
QUESTION: why I can not see the output send by the program?
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 2048
//http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html#idp22656
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
struct ifreq ifr;
size_t if_name_len;
char packet[BUF_SIZE];
struct ether_header *eh;
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
u_int16_t src_port, dst_port;
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};
memset(packet, 0, sizeof(packet));
eh = (struct ether_header *) packet;
iph = (struct iphdr *) (packet + sizeof(struct ether_header));
udph = (struct udphdr *) (packet + sizeof(struct ether_header) + sizeof(struct iphdr));
data = (char *)packet + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
// create raw socket to send/receive ethernet frames that can transport all protocols
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
strcpy(data, "hhhhhhhhh");
tx_len += strlen(data);
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(data)); //sizeof(sec_payload)); //20+8+64
iph->id = htons(54321);
iph->frag_off = 0x00;
iph->ttl = 0xFF;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
iph->check = ip_checksum(iph, iph->ihl << 2);
// build udp header
udph->source = htons(8090);
udph->dest = htons(8091);
udph->len = htons(sizeof(struct udphdr) + strlen(data));//sizeof(sec_payload));
udph->check = 0;
memset(&dst_addr, 0, sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
if (sendto(sockfd, packet, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
You used same source and destination ip address. Just changing the source address to fake makes it work. Linux kernel must be dropping the packet, because it doesn't think it originated it.
I've found that on my linux box disabling Reverse Path Filtering for test purposes (sudo sysctl -w 'net.ipv4.conf.all.rp_filter=0') fixed the issue. I was able to send and receive crafted udp packets on same host.
Reverse Path Filtering feature seems to be used for mitigating attacks using ip address spoofing. What may explain why in your case the packet was never delivered to net cat application.

Incorrect and variable IP packet checksum value

GOAL: crafting a packet from zero and send it.
PROBLEM: after I enabled "validate checksum" on wireshark I noticed that the expected checksum value should be 0xa85d but the checksum function I'm using computes a different value each time. Why the checksum is changing if the packet is always the same? What is the cause of the checksum mismatch between the one I compute and the one expected by wireshark? Thanks
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 1024
// https://gist.github.com/leonid-ed/909a883c114eb58ed49f
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
struct ifreq ifr;
size_t if_name_len;
char buf[BUF_SIZE];
struct ether_header *eh = (struct ether_header *) buf;
struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct ether_header) + sizeof(struct iphdr));
unsigned char *data = buf + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
u_int16_t src_port, dst_port;
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};
// create raw socket to send/receive ethernet frames that can transport all protocols
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
memset(&sec_payload,5,sizeof(struct seccomp_data));
data = (char*)malloc(sizeof(struct seccomp_data));
memcpy(data, (const unsigned char *)&sec_payload, sizeof(struct seccomp_data));
int i;
for(i=0;i<sizeof(sec_payload);i++){
buf[tx_len++] = data[i];
printf("%02X ",data[i]);
}
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload));
iph->id = htons(54321);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
// build udp header
udph->source = htons(8090);
udph->dest = htons(8091);
udph->len = htons(sizeof(struct udphdr) + sizeof(sec_payload));
iph->check = csum((unsigned short *)buf, sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload));
memset(&dst_addr,0,sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
if (sendto(sockfd, buf, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}

TCP SYN flood using raw socket in ubuntu

I'm trying to make a TCP SYN flood between two ubuntu machines (I'm using virtualbox, and i do have ping between the machines).
The error I get is
ERROR setting IP_HDRNICL.
ERROR number:9.
ERROR message:Bad file descriptor.
I guess it's related that I'm using virtualbox machines so how can I make this tcp syn flood to work without setting IP_HDRINCL?
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
struct pseudo_header
{
unsigned int source_address;
unsigned int dest_address;
unsigned char placeholder;
unsigned char protocol;
unsigned short tcp_length;
struct tcphdr tcp;
};
unsigned short csum(unsigned short *ptr,int nbytes) {
register long sum;
unsigned short oddbyte;
register short answer;
sum=0;
while(nbytes>1) {
sum+=*ptr++;
nbytes-=2;
}
if(nbytes==1) {
oddbyte=0;
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}
sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;
return(answer);
}
int main (void)
{
//Create a raw socket
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
//Datagram to represent the packet
char datagram[4096] , source_ip[32];
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//TCP header
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
struct pseudo_header psh;
strcpy(source_ip , "192.168.56.101");
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("1.2.3.4");
memset (datagram, 0, 4096); /* zero out the buffer */
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
iph->id = htons(54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
//TCP Header
tcph->source = htons (1234);
tcph->dest = htons (80);
tcph->seq = 0;
tcph->ack_seq = 0;
tcph->doff = 5; /* first and only tcp segment */
tcph->fin=0;
tcph->syn=1;
tcph->rst=0;
tcph->psh=0;
tcph->ack=0;
tcph->urg=0;
tcph->window = htons (5840); /* maximum allowed window size */
tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
should fill in the correct checksum during transmission */
tcph->urg_ptr = 0;
//Now the IP checksum
psh.source_address = inet_addr( source_ip );
psh.dest_address = sin.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(20);
memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));
tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));
//IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
{
printf ("Error setting IP_HDRINCL. Error number : %d . Error message : %s \n" , errno , strerror(errno));
exit(0);
}
//Uncommend the loop if you want to flood :)
//while (1)
//{
//Send the packet
if (sendto (s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->tot_len, /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof (sin)) < 0) /* a normal send() */
{
printf ("error\n");
}
//Data send successfully
else
{
printf ("Packet Send \n");
}
//}
return 0;
}
You need to have root in order to use raw socket. I have the exact same error message when I run your programm without root permissions but it is working fine when launched with root permissions.

Raw socket sendto failed using C on Linux

I'm trying to send a raw packet using UDP, with the IP and UDP headers that I have constructed in my code. Raw packet successfully initialized with socket(PF_INET, SOCK_RAW, IPPROTO_UDP) and socket option set using setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)).
The problem is when I send the packet using sendto(), I get the error 'Message too long'.
My IP header is 20 bytes and UDP header 8 bytes and my data is 12 bytes. So the total is only 40 bytes. This can't possibly be too long for a single UDP packet. Can someone help?
The type of val is a pointer to an int
Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
//The packet length in byes
#define PCKT_LEN 50
//Date size in bytes
#define DATA_SIZE 12
//PseudoHeader struct used to calculate UDP checksum.
typedef struct PseudoHeader{
unsigned long int source_ip;
unsigned long int dest_ip;
unsigned char reserved;
unsigned char protocol;
unsigned short int udp_length;
}PseudoHeader;
// Ripped from Richard Stevans Book
unsigned short ComputeChecksum(unsigned char *data, int len)
{
long sum = 0; /* assume 32 bit long, 16 bit short */
unsigned short *temp = (unsigned short *)data;
while(len > 1){
sum += *temp++;
if(sum & 0x80000000) /* if high order bit set, fold */
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if(len) /* take care of left over byte */
sum += (unsigned short) *((unsigned char *)temp);
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return ~sum;
}
int BindRawSocketToInterface(int rawsock, char *addr, short int port)
{
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = inet_addr(addr);
s_addr.sin_port = htons(port);
if((bind(rawsock, (struct sockaddr *)&s_addr, sizeof(s_addr)))== -1)
{
perror("Error binding raw socket to interface\n");
exit(-1);
}
return 1;
}
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
struct ip *CreateIPHeader(char *srcip, char *destip)
{
struct ip *ip_header;
ip_header = (struct ip *)malloc(sizeof(struct ip));
ip_header->ip_v = 4;
ip_header->ip_hl = 5;
ip_header->ip_tos = 0;
ip_header->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
ip_header->ip_id = htons(111);
ip_header->ip_off = 0;
ip_header->ip_ttl = 111;
ip_header->ip_p = IPPROTO_TCP;
ip_header->ip_sum = 0; /* We will calculate the checksum later */
inet_pton(AF_INET, srcip, &ip_header->ip_src);
inet_pton(AF_INET, destip, &ip_header->ip_dst);
/* Calculate the IP checksum now :
The IP Checksum is only over the IP header */
ip_header->ip_sum = ComputeChecksum((unsigned char *)ip_header, ip_header->ip_hl*4);
return (ip_header);
}
// Creates a the UDP header.
struct udphdr *CreateUdpHeader(char *srcport, char *destport )
{
struct udphdr *udp_header;
/* Check netinet/udp.h for header definiation */
udp_header = (struct udphdr *)malloc(sizeof(struct udphdr));
udp_header->source = htons(atoi(srcport));
udp_header->dest = htons(atoi(destport));
udp_header->len = htons(sizeof(struct udphdr) + DATA_SIZE); //TODO: need to specify this
udp_header->check = htons(0);
return (udp_header);
}
void CreatePseudoHeaderAndComputeUdpChecksum(struct udphdr *udp_header, struct ip *ip_header, unsigned char *data)
{
/*The TCP Checksum is calculated over the PseudoHeader + TCP header +Data*/
/* Find the size of the TCP Header + Data */
int segment_len = ntohs(ip_header->ip_len) - ip_header->ip_hl*4;
/* Total length over which TCP checksum will be computed */
int header_len = sizeof(PseudoHeader) + segment_len;
/* Allocate the memory */
unsigned char *hdr = (unsigned char *)malloc(header_len);
/* Fill in the pseudo header first */
PseudoHeader *pseudo_header = (PseudoHeader *)hdr;
pseudo_header->source_ip = ip_header->ip_src.s_addr;
pseudo_header->dest_ip = ip_header->ip_dst.s_addr;
pseudo_header->reserved = 0;
pseudo_header->protocol = ip_header->ip_p;
pseudo_header->udp_length = htons(segment_len);
/* Now copy TCP */
memcpy((hdr + sizeof(PseudoHeader)), (void *)udp_header, 8);
/* Now copy the Data */
memcpy((hdr + sizeof(PseudoHeader) + 8), data, DATA_SIZE);
/* Calculate the Checksum */
udp_header->check = ComputeChecksum(hdr, header_len);
/* Free the PseudoHeader */
free(hdr);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
char buffer[PCKT_LEN];
char *data = "Hello World!";
// Source and destination addresses: IP and port
struct sockaddr_in to_addr;
int one = 1;
const int *val = &one;
printf("IP Header Size: %lu \n", sizeof(struct ip));
printf("UDP Header Size: %lu \n", sizeof(struct udphdr));
printf("Data Size: %d\n", DATA_SIZE);
printf("IP Total: %lu \n", sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
//Bind the socket to the source address and port.
BindRawSocketToInterface(sd, argv[1], atoi(argv[2]));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) < 0)
{
perror("setsockopt() error");
close(sd);
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// The source is redundant, may be used later if needed
// The address family
to_addr.sin_family = AF_INET;
to_addr.sin_addr.s_addr = inet_addr(argv[3]);
to_addr.sin_port = htons(atoi(argv[4]));
//Create the IP header.
struct ip *ip_header = CreateIPHeader(argv[1], argv[3]);
//Create the UDP header.
struct udphdr *udp_header = CreateUdpHeader(argv[2], argv[4]);
//Compute UDP checksum
CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
//Copy IP header, UDP header, and data to the packet buffer.
memcpy(buffer, ip_header, sizeof(struct ip));
memcpy(buffer + sizeof(struct ip), udp_header, 8 /*sizeof(struct udphdr)*/);
memcpy(buffer + sizeof(struct ip) + 8, data, DATA_SIZE);
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
{
perror("sendto() error");
}
else
{
printf("sendto() is OK.\n");
}
free(ip_header);
free(udp_header);
close(sd);
return 0;
}
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
The length here is wrong, you should not specify that in network byte order.
A simple 20 is enough. htons(20) will be a very large number on a little endian machine.
( if you want to send other things that just the IP header, you should include that too in the length,, sounds like your buffer is 40 bytes, not 20)
You can use my own function that i don't have your problem:
#define NDEBUG
#define COUNTMAX 3000
#define MAX_FAKE 100
#define ERROR -1
#define TYPE_A 1
#define TYPE_PTR 12
#define CLASS_INET 1
#define ERROR -1
#ifndef IPVERSION
#define IPVERSION 4
#endif /* IPVERISON */
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define DNSHDRSIZE 12
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define IPHDRSIZE sizeof(struct iphdr)
#define UDPHDRSIZE sizeof(struct udphdr)
int udp_send(int s, unsigned long saddr, unsigned long daddr,unsigned short sport,unsigned short dport,char *datagram, unsigned datasize)
{
struct sockaddr_in sin;
struct iphdr *ip;
struct udphdr *udp;
unsigned char *data;
unsigned char packet[4024];
ip = (struct iphdr *)packet;
udp = (struct udphdr *)(packet+IPHDRSIZE);
data = (unsigned char *)(packet+IPHDRSIZE+UDPHDRSIZE);
memset(packet,0,sizeof(packet));
udp->source = htons(sport);
udp->dest = htons(dport);
udp->len = htons(UDPHDRSIZE+datasize);
udp->check = 0;
memcpy(data,datagram,datasize);
ip->saddr.s_addr = saddr;
ip->daddr.s_addr = daddr;
ip->version = 4; /*ip version*/
ip->ihl = 5;
ip->ttl = 245;
ip->id = random()%5985;
ip->protocol = IPPROTO_UDP; /*protocol type*/
ip->tot_len = htons((IPHDRSIZE + UDPHDRSIZE + datasize));
ip->check = 0;
ip->check = in_cksum((char *)packet,IPHDRSIZE);
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=daddr;
sin.sin_port=udp->dest;
printf ("socket: %d, packet: %s,size: %d, struct addr: %p, size: %i", s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, (struct sockaddr*)&sin, sizeof(struct sockaddr));
return sendto(s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, 0, (struct sockaddr*)&sin, sizeof(struct sockaddr));
}// end of udp_send function
The call to sendto() doesn't appear to be right as shown, even corrected per the comments:
Original: sendto(sd, buffer, htons(20)/ip_header->ip_len/,...);
Orr as corrected: sendto(sd, buffer, 20/ip_header->ip_len/,...);
The data length parameter should be the sum of header and data lengths: 20+8+12 = 40. A general solution could be:
sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE,...);
With this change it started working for me.

Resources