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
?
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.