Socket raw, can't get response from tcp server in tcp handshake - c

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

Related

c source code for establishing connection using cotp with raw socket

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

Why is my router dropping packets from my raw sockets application?

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.

Problem with create filter on IP=127.0.0.1 and interface='enp0s3'

port = 1, IP = 127.0.0.1, interface = enp0s3.
Hello friends my problem is that funkcion pcap_loop() dont want working i dont understand bc if i change IP on 127.0.0.0 and interface on 'lo' later funkcion working normal. I think that mistake is here
char filter_exp[40];
sprintf(filter_exp, "port %d", port)
but i am not sure. If you can help me i will be grateful.
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if ( sock == -1 )
{
printf("Error while creating socket\n");
exit(-1);
}
char datagram[4096] , source_ip[32] , *data , *pseudogram;
memset (datagram, 0, 4096);
struct iphdr *iph = (struct iphdr *) datagram;
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct iphdr));
struct sockaddr_in sin;
struct pseudo_header psh;
data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr);
strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
strcpy(source_ip , IP);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = inet_addr(IP);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + strlen(data);
iph->id = htonl(54321);
iph->frag_off = 0x00;
iph->ttl = 0xFF;
iph->protocol = IPPROTO_TCP;
iph->check = 0;
iph->saddr = inet_addr(IP);
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum((unsigned short *) datagram, iph->tot_len);
tcph->source = htons(1234);
tcph->dest = htons(port);
tcph->seq = 0x0;
tcph->ack_seq = 0x0;
tcph->doff = 5;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->window = htons(155);
tcph->check = 0;
tcph->urg_ptr = 0;
tcph->res1 = 0;
tcph->cwr = 0;
tcph->ece = 0;
psh.source_address = inet_addr(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);
int one = 1;
if ( setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0 )
{
perror("Error while setting socket options");
exit(1);
}
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[40];
sprintf(filter_exp, "port %d", port);
bpf_u_int32 mask;
bpf_u_int32 net;
if ( setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0 )
{
perror("Error while setting socket options");
exit(-1);
}
if ( pcap_lookupnet(interface->ifa_name, &net, &mask, errbuf) == -1 )
{
fprintf(stderr, "Can't get netmask for device %s\n", interface->ifa_name);
net = 0;
mask = 0;
}
handle = pcap_open_live(interface->ifa_name, BUFSIZ, 1, 1000, errbuf);
if ( handle == NULL )
{
fprintf(stderr, "Couldn't open device %s: %s\n", interface->ifa_name, errbuf);
exit(1);
}
if ( pcap_compile(handle, &fp, filter_exp, 0, net) == -1 )
{
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
exit(1);
}
if ( pcap_setfilter(handle, &fp) == -1 )
{
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
exit(1);
}
if ( sendto(sock, datagram, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0 )
{
printf("Sending packet failed\n");
exit(1);
}
printf("%d/tcp ", port);
//Here crash
pcap_loop(handle, 1, callBack, NULL);
pcap_close(handle);
printf("\n"
"enp0s3" is an Ethernet interface, as per this question on a forum.
You should not get ANY traffic to, or from, 127.0.0.1 on an Ethernet interface; that traffic will be sent by the machine to itself over the "loopback" interface, which is "lo" on Linux.

How to set custom syn/ack value in a TCP packet in C?

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 :)

broadcast packets sent from tap interface not received

I am making a program similar to simpletun from here.
an application sends out UDP broadcasts to the tap interface.
program listening on the tap interface (similar to simpletun)receives the packet and echoes it again as broadcast.
I am able to see both the packets on wireshark but the application does not receive it. seems that the kernel is dropping them.
If similar packets are sent from a different machine . it works fine.
tun/tap code:-
char datagram[4096];
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;
};
struct pseudo_header psh;
char *pseudogram;
nread = cread(tap_fd, buffer, BUFSIZE);
memcpy(&source_port,(char *)(buffer+14+20),2);
memset (datagram, 0, 4096);
memcpy(datagram,buffer,14); //copy eth-header
datagram[6] = 0xXX;//change mac address
datagram[7] = 0xXX;
datagram[8] = 0xXX;
//IP header
struct iphdr *iph = (struct iphdr *) (datagram +14);
//TCP header
struct udphdr *udph = (struct udphdr *) (datagram + 14 + sizeof (struct iphdr));
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr) +14;
strcpy(data,"Any string");
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
strcpy(source_ip , "192.168.0.99");
iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address
strcpy(destination_ip , "255.255.255.255");
iph->daddr = inet_addr (destination_ip);
udph->source = htons(5933);
//udph->dest = htons(source_port);
udph->dest = (source_port);
udph->len = htons(sizeof(struct udphdr) + strlen(data));
//Now the UDP checksum
psh.source_address = inet_addr( source_ip );
psh.dest_address = inet_addr(destination_ip);
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));
memcpy(pseudogram + sizeof(struct pseudo_header) + sizeof(struct udphdr), data , strlen(data));
udph->check = 0;
udph->check = csum( (unsigned short*) pseudogram , psize);
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//writeback
cwrite(tap_fd,datagram,iph->tot_len +14);
The above code when run from another machine using raw sockets read and write works well. (without eth-header).
Receiving Application code:-
int broadcast =1;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,"tun0",5);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
memset(&my_addr.sin_addr.s_addr,255,sizeof(my_addr.sin_addr.s_addr));
ret = setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&broadcast,sizeof(broadcast));
if(ret<0)
printf("setsockopt bindto failed");
if (sendto(sockfd,buf,500,0, (struct sockaddr*)&my_addr,slen_len) == -1)
err("send()");
recvfrom(sockfd, buf, 500, 0, (struct sockaddr*)&cli_addr, &slen);
Have you checked the host firewall rules ?
Solved it by using proper checksum and proper byte order for tot_len for ip header
iph->tot_len = (htons)sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
iph->id = htons (54321); //Id of this packet
iph->check = htons(csum ((unsigned short *) datagram,sizeof(struct ip_hdr)));
**where csum is a common function to calculate checksum.
from a different machine packet was received because kernel's network stack was recalculating iph->tot_len and the ip checksum. so the packet was properly formed.
with my tun interface after correcting the checksum and byteorder of tot_len packet was received by the application.
Shot in the dark guess:
But you could try changing your TUN/TAP code be setting the destination MAC address to broadcast (FF:FF:FF:FF:FF:FF) when it sees the IP destination as the broadcast IP (255.255.255.255)?

Resources