Raw Socket Code – IP_HDRINCL Code example

The previous code example (provided here) showed the usage of IPPROTO_RAW. In the current example, the protocol field is kept as IPPROTO_UDP (or any L4 protocol). However, the setsockopt API is used to set the IP_HDRINCL flag. The setting of this flag will again stop the kernel from adding the IP header and the onus is on the application to append the IP header by itself.

The sample code is provided below

Raw Socket IP_HDRINCL example

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

        int IP_HDRINCL_ON = 1;

        signal (SIGINT, interrupt_handler);
        signal (SIGTERM, interrupt_handler);

        if (0 > (raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP))) {
                printf(“Unable to create a socket\n”);
                exit(0);
        }

        if(setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &IP_HDRINCL_ON, sizeof(IP_HDRINCL_ON)) < 0) {
                printf(“Unable to set socket options \n”);
                goto end;
        }

        /* 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 output is the same as the previous IPPROTO_RAW example code output and is shown below

IPv6 Socket Code Example

Comments

  1. Pingback: Raw Socket Code – IPPROTO_RAW example | Hitch Hiker's Guide to Learning

Leave a Reply

Your email address will not be published. Required fields are marked *