vishal kumar
vishal kumar

Reputation: 65

How to parse an IP Packet stored in char buffer in C/C++

I have an IP packet stored in a char buffer:

char packet[] = "450000CC68C4000001114C4F0A0A0A0AEFFFFFFADEA9076C00B832074D2D534541524348202A20485454502F312E310D0A484F53543A203233392E3235352E3235352E3235303A313930300D0A4D414E3A2022737364703A646973636F766572220D0A4D583A20310D0A53543A2075726E3A6469616C2D6D756C746973637265656E2D6F72673A736572766963653A6469616C3A310D0A555345522D4147454E543A20476F6F676C65204368726F6D652F3130372E302E353330342E313130204D6163204F5320580D0A0D0A"

I am try to parse this IP header using netinet/ip.h ip definition.

But when i try to print the ip packet details like ip header length, it is printing garbage:

#include <netinet/ip.h>

    void decodeIPPacket(const char *packet)
    {
        struct ip *ipHdr = (struct ip*)(long)packet;
        
        printf("decodeIPPacket:: IP Len: %d", ipHdr->ip_len);
        printf("decodeIPPacket:: srcip: %u", ipHdr->ip_src.s_addr);
        printf("decodeIPPacket:: dstip: %u", ipHdr->ip_dst.s_addr);
    }

decodeIPPacket:: IP Len: 12336

decodeIPPacket:: srcip: 808464432

decodeIPPacket:: dstip: 825307440

What am i doing wrong here?

Upvotes: 2

Views: 828

Answers (1)

Iman Seyed
Iman Seyed

Reputation: 399

Every character in your string represent a nybble in hexadecimal. You need to convert every 2 char from ASCII to hexadecimal as a byte.

#include <netinet/ip.h>
#include <stdio.h>
#include <string.h>

char string[] =
    "450000CC68C4000001114C4F0A0A0A0AEFFFFFFADEA9076C00B832074D2D53454152434820"
    "2A20485454502F312E310D0A484F53543A203233392E3235352E3235352E3235303A313930"
    "300D0A4D414E3A2022737364703A646973636F766572220D0A4D583A20310D0A53543A2075"
    "726E3A6469616C2D6D756C746973637265656E2D6F72673A736572766963653A6469616C3A"
    "310D0A555345522D4147454E543A20476F6F676C65204368726F6D652F3130372E302E3533"
    "30342E313130204D6163204F5320580D0A0D0A";

int main() {
    char *pos = string;
    int packetLen = strlen(string) / 2;
    unsigned char packet[packetLen];
    struct sockaddr_in source, dest;

    /* Read only 20 bytes (40 nybbles) 
     * to store only IPv4 header.
     * NOTE: IPv4 header is not always 
     * 20 bytes. Can contain 'options' field.
     * You have to extract ihl value first.
     */
    for (size_t i = 0; i < 40; ++i) {
        sscanf(pos, "%2hhx", &packet[i]);
        pos += 2;
    }

    struct iphdr *iph = (struct iphdr *)packet;
    memset(&source, 0, sizeof(source));
    source.sin_addr.s_addr = iph->saddr;

    memset(&dest, 0, sizeof(dest));
    dest.sin_addr.s_addr = iph->daddr;

    printf("IP Version: %d\n", (unsigned int)iph->version);
    printf("IP Header Length: %d Bytes\n", ((unsigned int)(iph->ihl)) * 4);
    printf("Type Of Service: %d\n", (unsigned int)iph->tos);
    printf("IP Total Length: %d  Bytes(Size of Packet)\n",
           ntohs(iph->tot_len));
    printf("Identification: %d\n", ntohs(iph->id));
    printf("TTL: %d\n", (unsigned int)iph->ttl);
    printf("Protocol: %d\n", (unsigned int)iph->protocol);
    printf("Checksum: %d\n", ntohs(iph->check));
    printf("Source Adddress: %.4x\n", source.sin_addr);
}

Output:

IP Version: 4
IP Header Length: 20 Bytes
Type Of Service: 0
IP Total Length: 204  Bytes(Size of Packet)
Identification: 26820
TTL: 1
Protocol: 17
Checksum: 19535
Source Adddress: a0a0a0a
Destination Adddress: faffffef

Upvotes: 3

Related Questions