go: x/net/ipv4: add IPv4 header checksum computation for ipv4.Header type
I’m working on a project that uses packet sockets directly, and I have to calculate the IPv4 checksum on my own since I’m building from Ethernet frames up.
I notice that x/net/ipv4 doesn’t provide any way to easily calculate a checksum, but I think such a function/method could be useful in conjunction with the ipv4.Header type.
I wrote a basic implementation in ~30 lines with documentation comments, and would be happy to submit it upstream. At this point, my questions are:
- Is this something that would be considered generally useful enough to go in
x/net/ipv4? - If so, what should the API look like?
My current implementation accepts a byte slice from the output of ipv4.Header.Marshal, but I could see a method making sense as well.
// ipv4Checksum computes the IPv4 header checksum for input IPv4 header bytes.
func ipv4Checksum(b []byte) (uint16, error) {
// ...
}
/cc @mikioh
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 4
- Comments: 24 (23 by maintainers)
I’m not @mdlayher or @mikioh, but as someone recently interested in this code, I can try to explain what I believe to be going on.
Let’s say you created a raw socket and print the first packet you receive.
On Linux, the bytes you receive are the same bytes received over the wire. Computing the IPv4 checksum over
buf[:n]using the CL function results in the same value as we received,0x4531.On at least some versions of Darwin, FreeBSD, NetBSD, and DragonFlyBSD this assumption isn’t true, the values may be significantly different. FreeBSD’s
ip(4)for example:The checksum value received on the raw connection would be what was seen “on-the-wire” (that is, with these fields in network byte order). Computing a checksum separately by using the output of
Marshalon those systems would result in differing values.I’d suggest updating the documentation of
ipv4.Header.Checksumto something along the lines of “wire header checksum”. As far as I know, when sending raw packets, if set to 0 it will be filled in by all kernels, even if theIP_HDRINCLoption is providedI still want to see some better docs at least. @mikioh confused me and if I ever look at this field again, I’d like to know what it means.