Overview

 ____  _ _     ____                          
| __ )(_) |_  |  _ \ __ _ _ __ ___  ___ _ __ 
|  _ \| | __| | |_) / _` | '__/ __|/ _ \ '__|
| |_) | | |_  |  __/ (_| | |  \__ \  __/ |   
|____/|_|\__| |_|   \__,_|_|  |___/\___|_|   


An IPv4 packet header looks like:

bit offset  |  0-3   |  4-7   |  8-13  |  14-15  |  16-18  |  19-31  |
------------+--------+--------+--------+---------+---------+---------+
   0        |version | IHL    | DSCP   | ECN     | Total  Length     |
------------+--------+--------+--------+---------+---------+---------+
  32        |            Identification          | Flags   | Offset  |
------------+-----------------+------------------+---------+---------+
  64        |   TTL           |  Protocol        |  Checksum         |
------------+-----------------+------------------+-------------------+
  96        |           Source IP Address                            |
------------+--------------------------------------------------------+
 128        |           Destination IP Address                       |
------------+--------------------------------------------------------+

If you have one:

  unsigned char ip_packet[32] = {
    0x45, 0x00, 0x00, 0x48, 0xaa, 0xcd, 0x00, 0x00, 0xff, 0x11, 0x8c, 0x22, 0xc0, 0xa8, 0x01, 0x66,
    0xc0, 0xa8, 0x01, 0xfe, 0xe6, 0xf0, 0x00, 0x35, 0x00, 0x34, 0xa1, 0x37, 0x2e, 0xc3, 0x01, 0x00
  };

You can use bit parser to read it, with the "bitscanf" function:

  #include <stdio.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>

  #include "bits.h"

  unsigned long long version, header_length, dscp, ecn, total_length, identification, flags, offset,
                ttl, protocol, checksum, src, dst;
  struct sockaddr_in addr;

  /* here's bitscanf ! */
  bitscanf(ip_packet, "%4b%4b%6b%2b%16b%16b%3b%13b%8b%8b%16b%32b%32b",
      &version, &header_length, &dscp, &ecn, &total_length, 
      &identification, &flags, &offset,
      &ttl, &protocol, &checksum, &src, &dst);

  printf("ip packet:\n");
  printf(" version: %llu\n", version);
  printf(" header length: %llu\n", header_length);
  printf(" dscp: %llu\n", dscp);
  printf(" ecn: %llu\n", ecn);
  printf(" total length: %llu\n", total_length);
  printf(" identification: %llu\n", identification);
  printf(" flags: %llu\n", flags);
  printf(" offset: %llu\n", offset);
  printf(" ttl: %llu\n", ttl);
  printf(" protocol: %llu\n", protocol);
  printf(" checksum: %llu\n", checksum);
  addr.sin_addr.s_addr =  htonl(src);
  printf(" source: %s\n", inet_ntoa(addr.sin_addr));
  addr.sin_addr.s_addr =  htonl(dst);
  printf(" destination: %s\n", inet_ntoa(addr.sin_addr));