We have not seen the usage of IPPROTO_RAW as a protocol in all of the previous articles. The current article provides a code example for IPPROTO_RAW as the protocol field in the socket API.
If IPPROTO_RAW is used, then the IP header needs to be formulated by the application. The sample code fills in a sample IP header and keeps retransmitting the same packet.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <linux/udp.h> /* UDP Header */
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <linux/ip.h>
#define DEBUG 0
struct sockaddr_in *clientaddr = NULL;
int raw_socket;
int SERVPORT=30000;
int DESTPORT=30001;
/* structure to calculate UDP checksum
* The below members are part of the IP header
* which do not change from the UDP layer and hence
* are used as a part of the UDP checksum */
struct pseudo_iphdr {
unsigned int source_ip_addr;
unsigned int dest_ip_addr;
unsigned char fixed;
unsigned char protocol;
unsigned short udp_len;
};
/* checksum code to calculate UDP 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(raw_socket);
free(clientaddr);
exit(0);
}
void main () {
socklen_t length, num_of_bytes;
char buffer[1024] = {0};
unsigned char recvbuffer[1024] = {0};
char *string = “Hello client\n”;
struct udphdr *udp_hdr = NULL;
struct iphdr *ip_hdr = NULL;
char *string_data = NULL;
char *recv_string_data = NULL;
char *csum_buffer = NULL;
struct pseudo_iphdr csum_hdr;
signal (SIGINT, interrupt_handler);
signal (SIGTERM, interrupt_handler);
if (0 > (raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))) {
printf(“Unable to create a socket\n”);
exit(0);
}
/* Part 2 – create the server connection – fill the structure*/
clientaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
if (clientaddr == NULL) {
printf(“Unable to allocate memory\n”);
goto end;
}
clientaddr->sin_family = AF_INET;
clientaddr->sin_port = htons(DESTPORT);
clientaddr->sin_addr.s_addr = inet_addr(“127.0.0.1”);
memset(buffer, 0, sizeof(buffer));
/* copy the data after the UDP header */
string_data = (char *) (buffer + sizeof(struct udphdr) + sizeof (struct iphdr));
strncpy(string_data, string, strlen(string));
/* Modify some parameters to send to client in UDP hdr
* code will perform a syn burst (flood) to the receive side */
udp_hdr = (struct udphdr *)(buffer + sizeof (struct iphdr));
udp_hdr->source = htons(SERVPORT);
udp_hdr->dest = htons(DESTPORT);
udp_hdr->len = htons(sizeof(struct udphdr));
/* calculate the UDP checksum – based on wikipedia
* pseudo IP header + UDP HDR +
* UDP data- check sum is calculated.
* create a buffer to calculate CSUM and calculate CSUM*/
csum_buffer = (char *)calloc((sizeof(struct pseudo_iphdr) + sizeof(struct udphdr) + 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(“127.0.0.1”);
csum_hdr.dest_ip_addr = inet_addr(“127.0.0.1”);
csum_hdr.fixed = 0;
csum_hdr.protocol = IPPROTO_UDP; /* UDP protocol */
csum_hdr.udp_len = htons(sizeof(struct udphdr) + strlen(string_data) + 1);
memcpy(csum_buffer, (char *)&csum_hdr, sizeof(struct pseudo_iphdr));
memcpy(csum_buffer + sizeof(struct pseudo_iphdr), buffer, (sizeof(struct udphdr) + strlen(string_data) + 1));
udp_hdr->check = (in_cksum((unsigned short *) csum_buffer,
(sizeof(struct pseudo_iphdr)+ sizeof(struct udphdr) + strlen(string_data) + 1)));
printf(“checksum is %x\n”, udp_hdr->check);
/* since we are resending the same packet over and over again
* free the csum buffer here */
free (csum_buffer);
/* Add IP Header */
ip_hdr = (struct iphdr *)buffer;
ip_hdr->ihl = 5; /* header length 5 * sizeof(uint32) = 20 bytes – no optional elements*/
ip_hdr->version = 4; /* ip version 4 */
ip_hdr->tos = 0; /* type of service */
ip_hdr->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(string_data) + 1;
ip_hdr->ttl = 64; /* time to live */
ip_hdr->protocol = IPPROTO_UDP;
ip_hdr->saddr = inet_addr(“127.0.0.1”); /* use loopback address for source */
ip_hdr->daddr = inet_addr(“127.0.0.1”); /* use loopback address for dest */
ip_hdr->check = in_cksum((unsigned short *)ip_hdr, sizeof(struct iphdr));
while (1) {
sleep(1);
num_of_bytes = sendto(raw_socket, buffer,(sizeof (struct iphdr) +
sizeof(struct udphdr)+strlen(string_data)+1), 0,
(struct sockaddr *)clientaddr, sizeof(struct sockaddr_in));
if (num_of_bytes == -1) {
printf(“unable to send Message\n”);
goto end1;
}
}
end1:
free (clientaddr);
end:
close (raw_socket);
return;
}
The wireshark capture below shows the packet being transmitted.
Pingback: Raw Socket Communication with Data Link Layer – code example | Hitch Hiker's Guide to Learning
Pingback: Raw Socket Code – IP_HDRINCL Code example | Hitch Hiker's Guide to Learning