For the below code, to understand the setup requirements, once can check the link below
Raw Socket Example with Connect and Bind API – setup
The below code creates the TCP header and basically resends the same TCP packet over and over again in a “while 1” loop. Run the server side code first and then the client code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <linux/ip.h>
#include <netinet/tcp.h>
struct sockaddr_in *servaddr = NULL, *client_addr = NULL;
int sock_fd;
#define PORT 50000
#define PORT_CLIENT 50001
/* structure to calculate TCP checksum
* The below members are part of the IP header
* which do not change from the TCP layer and hence
* are used as a part of the TCP checksum */
struct pseudo_iphdr {
unsigned int source_ip_addr;
unsigned int dest_ip_addr;
unsigned char fixed;
unsigned char protocol;
unsigned short tcp_len;
};
/* checksum code to calculate TCP checksum
* Code taken from Unix network programming – Richard stevens*/
unsigned short in_cksum (uint16_t * addr, int len)
{
int nleft = len;
unsigned int sum = 0;
unsigned short *w = addr;
unsigned short answer = 0;
/* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *) (&answer) = * (unsigned char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = (unsigned short) ~sum; /* truncate to 16 bits */
return (answer);
}
/* Interrupt_handler – so that CTRL + C can be used to
* exit the program */
void interrupt_handler (int signum) {
close(sock_fd);
free(client_addr);
exit(0);
}
#if DEBUG
/* print the IP and TCP headers */
void dumpmsg(unsigned char *recvbuffer, int length) {
int count_per_length = 40, i = 0;
for (i = 0; i < count_per_length; i++) {
printf(“%02x “, recvbuffer[i]);
}
printf(“\n”);
}
#endif
int main () {
char buffer[1024] = {0};
unsigned char recvbuffer[1024] = {0};
int length;
char *string = “Hello client”;
struct tcphdr *tcp_hdr = NULL;
char *string_data = NULL;
char *recv_string_data = NULL;
char *csum_buffer = NULL;
struct pseudo_iphdr csum_hdr;
int error;
signal (SIGINT, interrupt_handler);
signal (SIGTERM, interrupt_handler);
/* Part 1: create the socket */
sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(0 > sock_fd) {
printf(“unable to create socket\n”);
exit(0);
}
servaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
if (servaddr == NULL) {
printf(“could not allocate memory\n”);
goto end;
}
servaddr->sin_family = AF_INET;
servaddr->sin_port = PORT;
servaddr->sin_addr.s_addr = inet_addr(“192.168.1.11”);
/* Part 2 – fill data structure and bind to socket */
if (0 != (bind(sock_fd, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in)))) {
printf(“could not bind server socket to address\n”);
goto end1;
}
/* part 3: read and write data */
client_addr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
if (client_addr == NULL) {
printf(“Unable to allocate memory to client address socket\n”);
goto end2;
}
client_addr->sin_family = AF_INET;
client_addr->sin_port = PORT_CLIENT;
client_addr->sin_addr.s_addr = inet_addr(“192.168.1.14”);
error = connect(sock_fd, (struct sockaddr *)client_addr, sizeof(struct sockaddr_in));
if (error != 0) {
printf(“error %d”, errno);
printf(“connect returned error\n”);
goto end2;
}
/* copy the data after the TCP header */
string_data = (char *) (buffer + sizeof(struct tcphdr));
strncpy(string_data, string, strlen(string));
/* Modify some parameters to send to client in TCP hdr
* code will perform a syn burst (flood) to the receive side */
tcp_hdr = (struct tcphdr *)buffer;
tcp_hdr->source = htons(PORT);
tcp_hdr->dest = htons(PORT_CLIENT);
tcp_hdr->ack_seq = 0x0; /* seq number */
tcp_hdr->doff = 5; /* data_offset * 4 is TCP header size */
tcp_hdr->syn = 1; /* SYN flag */
tcp_hdr->window = htons(200); /* Window size scaling*/
/* calculate the TCP checksum – based on pseudo IP header + TCP HDR +
* TCP data. create a buffer to calculate CSUM and calculate CSUM*/
csum_buffer = (char *)calloc((sizeof(struct pseudo_iphdr) + sizeof(struct tcphdr) + strlen(string_data)), sizeof(char));
if (csum_buffer == NULL) {
printf(“Unable to allocate csum buffer\n”);
goto end1;
}
csum_hdr.source_ip_addr = inet_addr(“192.168.1.11”);
csum_hdr.dest_ip_addr = inet_addr(“192.168.1.14”);
csum_hdr.fixed = 0;
csum_hdr.protocol = IPPROTO_TCP; /* TCP protocol */
csum_hdr.tcp_len = htons(sizeof(struct tcphdr) + strlen(string_data) + 1);
memcpy(csum_buffer, (char *)&csum_hdr, sizeof(struct pseudo_iphdr));
memcpy(csum_buffer + sizeof(struct pseudo_iphdr), buffer, (sizeof(struct tcphdr) + strlen(string_data) + 1));
tcp_hdr->check = (in_cksum((unsigned short *) csum_buffer,
(sizeof(struct pseudo_iphdr)+ sizeof(struct tcphdr) + strlen(string_data) + 1)));
printf(“checksum is %x”, tcp_hdr->check);
/* since we are resending the same packet over and over again
* free the csum buffer here */
free (csum_buffer);
while (1) {
memset(recvbuffer, 0, sizeof(recvbuffer));
read(sock_fd, recvbuffer, sizeof(recvbuffer));
tcp_hdr = (struct tcphdr *)(recvbuffer + sizeof (struct iphdr));
recv_string_data = (char *) (recvbuffer + sizeof (struct iphdr) + sizeof (struct tcphdr));
#if DEBUG
dumpmsg((unsigned char *)&recvbuffer, (sizeof(struct iphdr) + sizeof(struct tcphdr)+ strlen(string_data) + 1));
#endif
if (PORT == ntohs(tcp_hdr->dest)) {
printf(“tcp destination is client %d, tcp window is %d\n”,ntohs(tcp_hdr->dest), ntohs(tcp_hdr->window));
printf(“data is %s\n”, recv_string_data);
}
write(sock_fd, buffer, sizeof(buffer));
}
end2:
free(client_addr);
end1:
free(servaddr);
end:
close(sock_fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <linux/ip.h>
struct sockaddr_in *serveraddr = NULL, *clientaddr;
int sockfd;
#define PORT 50001
#define SERVER_PORT 50000
/* structure to calculate TCP checksum
* The below members are part of the IP header
* which do not change from the TCP layer and hence
* are used as a part of the TCP checksum */
struct pseudo_iphdr {
unsigned int source_ip_addr;
unsigned int dest_ip_addr;
unsigned char fixed;
unsigned char protocol;
unsigned short tcp_len;
};
/* checksum code to calculate TCP checksum
* Code taken from Unix network programming – Richard stevens*/
unsigned short in_cksum (uint16_t * addr, int len)
{
int nleft = len;
unsigned int sum = 0;
unsigned short *w = addr;
unsigned short answer = 0;
/* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *) (&answer) = * (unsigned char *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = (unsigned short) ~sum; /* truncate to 16 bits */
return (answer);
}
/* Interrupt_handler – so that CTRL + C can be used to
* exit the program */
void interrupt_handler (int signum) {
close(sockfd);
free(clientaddr);
exit(0);
}
#if DEBUG
/* print the IP and TCP headers */
void dumpmsg(unsigned char *recvbuffer, int length) {
int count_per_length = 40, i = 0;
for (i = 0; i < count_per_length; i++) {
printf(“%02x “, recvbuffer[i]);
}
printf(“\n”);
}
#endif
int main () {
char buffer[1024] = {0};
unsigned char recvbuffer[1024] = {0};
int length;
char *string = “Hello server”;
struct tcphdr *tcp_hdr = NULL;
char *string_data = NULL;
char *recv_string_data = NULL;
char *csum_buffer = NULL;
struct pseudo_iphdr csum_hdr;
int error;
signal (SIGINT, interrupt_handler);
signal (SIGTERM, interrupt_handler);
/* Part 1: create the socket */
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(0 > sockfd) {
printf(“unable to create socket\n”);
exit(0);
}
clientaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
if (clientaddr == NULL) {
printf(“could not allocate memory\n”);
goto end;
}
clientaddr->sin_family = AF_INET;
clientaddr->sin_port = PORT;
clientaddr->sin_addr.s_addr = inet_addr(“192.168.1.14”);
/* Part 2 – fill data structure and bind to socket */
if (0 != (bind(sockfd, (struct sockaddr *)clientaddr, sizeof(struct sockaddr_in)))) {
printf(“could not bind server socket to address\n”);
goto end1;
}
/* part 3: read and write data */
serveraddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
if (serveraddr == NULL) {
printf(“Unable to allocate memory to server address socket\n”);
goto end2;
}
serveraddr->sin_family = AF_INET;
serveraddr->sin_port = SERVER_PORT;
serveraddr->sin_addr.s_addr = inet_addr(“192.168.1.11”);
error = connect(sockfd, (struct sockaddr *)serveraddr, sizeof(struct sockaddr_in));
if (error != 0) {
printf(“error %d”, errno);
printf(“connect returned error\n”);
goto end2;
}
/* copy the data after the TCP header */
string_data = (char *) (buffer + sizeof(struct tcphdr));
strncpy(string_data, string, strlen(string));
/* Modify some parameters to send to client in TCP hdr
* code will perform a syn burst (flood) to the receive side */
tcp_hdr = (struct tcphdr *)buffer;
tcp_hdr->source = htons(PORT);
tcp_hdr->dest = htons(SERVER_PORT);
tcp_hdr->ack_seq = 0x0; /* seq number */
tcp_hdr->doff = 5; /* data_offset * 4 is TCP header size */
tcp_hdr->syn = 1; /* SYN flag */
tcp_hdr->window = htons(200); /* Window size scaling*/
/* calculate the TCP checksum – based on pseudo IP header + TCP HDR +
* TCP data. create a buffer to calculate CSUM and calculate CSUM*/
csum_buffer = (char *)calloc((sizeof(struct pseudo_iphdr) + sizeof(struct tcphdr) + strlen(string_data)), sizeof(char));
if (csum_buffer == NULL) {
printf(“Unable to allocate csum buffer\n”);
goto end1;
}
csum_hdr.source_ip_addr = inet_addr(“192.168.1.14”);
csum_hdr.dest_ip_addr = inet_addr(“192.168.1.11”);
csum_hdr.fixed = 0;
csum_hdr.protocol = IPPROTO_TCP; /* TCP protocol */
csum_hdr.tcp_len = htons(sizeof(struct tcphdr) + strlen(string_data) + 1);
memcpy(csum_buffer, (char *)&csum_hdr, sizeof(struct pseudo_iphdr));
memcpy(csum_buffer + sizeof(struct pseudo_iphdr), buffer, (sizeof(struct tcphdr) + strlen(string_data) + 1));
tcp_hdr->check = (in_cksum((unsigned short *) csum_buffer,
(sizeof(struct pseudo_iphdr)+ sizeof(struct tcphdr) + strlen(string_data) + 1)));
printf(“checksum is %x”, tcp_hdr->check);
/* since we are resending the same packet over and over again
* free the csum buffer here */
free (csum_buffer);
while (1) {
write(sockfd, buffer, sizeof(buffer));
memset(recvbuffer, 0, sizeof(recvbuffer));
read(sockfd, recvbuffer, sizeof(recvbuffer));
tcp_hdr = (struct tcphdr *)(recvbuffer + sizeof (struct iphdr));
recv_string_data = (char *) (recvbuffer + sizeof (struct iphdr) + sizeof (struct tcphdr));
#if DEBUG
dumpmsg((unsigned char *)&recvbuffer, (sizeof(struct iphdr) + sizeof(struct tcphdr)+ strlen(string_data) + 1));
#endif
if (PORT == ntohs(tcp_hdr->dest)) {
printf(“tcp destination is client %d, tcp window is %d\n”,ntohs(tcp_hdr->dest), ntohs(tcp_hdr->window));
printf(“data is %s\n”, recv_string_data);
}
}
end2:
free(serveraddr);
end1:
free(clientaddr);
end:
close(sockfd);
return 0;
}
Pingback: Raw Socket Example with Connect and Bind API – setup | Hitch Hiker's Guide to Learning
Pingback: Analysis of Raw socket code with connect and Bind API | Hitch Hiker's Guide to Learning