I’m implementing a packet parser as a toy project to try and understand Zig better. As part of this I have headers of various sizes and at various offsets into the packet. I’m trying to figure out how I should be approaching this in Zig.
An example of the situation I currently have. In a Ethernet IPv4 packet the second u4 field contains the IHL, this describes how many 32 byte sections exist in the header of the IPv4 packet, after which the body (TCP / UDP etc) will be found.
If I have a pointer to the start of the IPv4 header, how do I gain a pointer to the start of the data section? I thought I’d be able to do this using pointer arithmetic, something along the lines of
dataPtr = ipv4Ptr + (IHL * 4) where the ptr is a ptr to u8.
I keep getting compilation errors about adding comptime ints or u8 to *u8 so in the end have gone down the following route of converting to a C ptr, but I feel like I’m doing things very wrong and abusing the language. What’s the proper Zig way of achieving this?
For reference data is a
*const u8 and ihl is a
const dataCPtr: [*c]const u8 = @ptrCast(data);
const ipDataPtr = dataCPtr + (@as(u8, ihl) * 4);
I did also briefly look at converting the pointer to an Int, doing the arithmetic and then converting back. I think I probably had other errors at the time so may be why I couldn’t get it working.
You are using the wrong pointer type for your data.
Zig has multiple pointer types: Documentation - The Zig Programming Language
You are using a single item pointer here. Because it is intended to always point at a single item it has no pointer arithmetic.
[*c] pointers are generally only intended to be used when interfacing with C functions.
For byte array I would recommend to use a slice
const u8 which is pointer plus a length and it can be incremented with the slicing syntax
Ah so I should have clarified, this is for interop with C, or at least, the data is fetched as a result of interop with C. I’m using libpcap to get packets from my network interface and as such the packet data comes back as a C pointer.
I’d be happy to switch to slices but my headers are variable sizes so not sure how I should be dealing with that. I also don;'t know the overall size of the packet and won’t know until I’ve parsed all the headers. How should I go about converting a C pointer into a slice or slice like structure to enable index based offsets?
In that case, since you don’t know the length, then I would suggest to use a multi-item pointer
[*]const u8. Multi-item pointer allow both pointer arithmetic and slicing.
Ah makes sense, not sure why I hadn’t thought of that, I’ll give it a go now and see how I get on. May have more questions