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