3

I'm trying to test a UDP program on what happens if it receives data with a bad UDP checksum. Strangely, it seems to have no effect, and the payload is received successfully, at least on OS X via the loopback interface.

An example is below, where data is sent using SOCK_RAW + IPPROTO_UDP, specifying the checksum manually to something incorrect, and received using SOCK_DGRAM.

import asyncio
import socket
import struct

async def server():
    with \
        socket.socket(
                socket.AF_INET, socket.SOCK_DGRAM
    ) as sock:
        sock.setblocking(False)
        sock.bind(('', 4567))
        payload = await loop.sock_recv(sock, 512)
        print(payload)  # Prints b'somedata'

async def main():
    asyncio.ensure_future(server())
    await asyncio.sleep(0)

    with socket.socket(
            family=socket.AF_INET, type=socket.SOCK_RAW, proto=socket.IPPROTO_UDP,
    ) as sock:

        local_ip = '127.0.0.1'
        src_port = 4566
        dest_port = 4567

        payload = b'somedata'
        length = 8 + len(payload)
        checksum = 3  # 3 is not the right checksum
        header_bad_checksum = struct.pack('!4H', src_port, dest_port, length, checksum)
        sock.sendto(header_bad_checksum + payload, (local_ip, 4567))

        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

Why is this? I would have expected the payload to be ignored.


The Wireshark dump of this UDP message is below, showing that (in this case) the checksum is 3.

enter image description here

Michal Charemza
  • 25,940
  • 14
  • 98
  • 165
  • As far as I can see, `sendto()` just sends bytes; it does not care about checksum validation. Do you have a documentation link that says otherwise? – John Gordon Apr 22 '19 at 16:42
  • @JohnGordon Well, no. But also, I would have expected the receiving end do the validation, rather than the sending, since I would have thought a purpose of the checksum is to catch errors introduced during transit. – Michal Charemza Apr 22 '19 at 17:09
  • Did you check if the checksum that you received is the same as the one you have transmitted? This may be caused by checksum offloading. Your NIC may be overriding the checksum calculation by the correct one. – hugos Apr 22 '19 at 17:17
  • @HugoSadok I have now included a screenshot from Wireshark that I think suggests it is the same. – Michal Charemza Apr 22 '19 at 17:22
  • Oh weird, it is also in the loopback interface, so it should not reach the NIC. – hugos Apr 22 '19 at 17:23
  • @MichalCharemza can you test this without using the loopback? I wouldn't be surprised if macOS simply ignores checksums in the loopback interface. – hugos Apr 22 '19 at 17:49
  • 2
    @HugoSadok After some initial tests, UDP packets with bad checksums from another computer on my network, are received with the bad checksums according to Wireshark, but then the socket in Python does not appear to receive them. So it does suggest macOS is ignoring them in the loopback interface. This is slightly annoying, since I was hoping to use the loopback interface as a "real" interface for tests, but it seems to behave differently in this respect. – Michal Charemza Apr 22 '19 at 18:16
  • @MichalCharemza Well it does make some sense if you think about it. It seems that Linux also behaves in the same way. You may consider using a VM on your tests. I know it's not ideal but at least you can use a single computer. – hugos Apr 23 '19 at 02:18

1 Answers1

1

This is expected behavior. From the f5 website

This is an expected behavior as tcpdump tool on Linux because the checksum is offloading on your NIC but tcpdump reads IP packets from the Linux kernel right before the actual checksum takes place in the NIC chipset.

Shōgun8
  • 482
  • 10
  • 20