Search code examples
pythoncasting

How to parse an IPv4 packet header in Python


I have some code in C that looks similar to this:


struct iphdr{
#if __BYTE_ORDER == __LITTLE_ENDIAN
  unsigned int ihl:               4;
  unsigned int version:           4;
#elif __BYTE_ORDER == __BIG_ENDIAN
  unsigned int version:           4;
  unsigned int ihl:               4;
#else
  #error "Please fix <bits/endian.h>"
#endif
  uint8_t tos;
  uint16_t tot_len;
  uint16_t id;
  uint16_t frag_off;
  uint8_t ttl;
  uint8_t protocol;
  uint16_t check;
  uint32_t saddr;
  uint32_t daddr;

};
...
...
...
unsigned char * ip_header_bytes = "\x45\x00\x00\xf8\xb8\xa7\x00\x40\x06\x81\x80\xac\x10\x44\x03\x22\x78\xed\x4c";
struct iphdr * ipdata = (struct iphdr *)ip_header_bytes;

And with that snippet I could access the various members within ipdata.

Now say I have a Python class that contains similar data to iphdr and I have a variable that contains the same data as ip_header_bytes. Is there a way I can populate a new instance of iphdr with the data from ip_header_bytes?


Solution

  • The C code relies on undefined behaviour. It doesn't have a predictable result. But you don't really care about that. What you're really asking is how to parse the header of an IPv4 packet.

    First of all, an IPv4 packet header is 20 bytes long, and you only have 19.

    Once you resolve that, you'd use struct.unpack to convert the bytes into numbers.

    import struct
    
    header_packed = b"...20 bytes..."
    header_values = struct.unpack( ">BBHHHBBHII", header_packed )
    

    The first two bytes each consist of two fields, so you'll need to follow up with bit operations to extract these.

    ihl     = header_values[0] >> 4;
    version = header_values[0] & 0xF;
    
    dscp    = header_values[1] >> 2;
    ecn     = header_values[1] & 0x3;
    

    And if you want ip address objects from the last two fields, you can use

    import ipaddress
    
    saddr = ipaddress.ip_address( header_values[8] )
    daddr = ipaddress.ip_address( header_values[9] )
    

    Creating a struct-like object in Python from the tuple and these extracted fields is left to you.