Linux udp checksum disable

Linux, UDP checksum, на заметку

При просмотре трафика через tcpdump -vvv, вижу, что он сообщает [bad udp cksum . ] о неправильной контрольной сумме любого UDP-пакета, проходящего через локальный интерфейс lo или, если используется виртуальная машина, через внешний виртуальный интерфейс. При этом поле контрольной суммы в пакете заполнено. Если пакет уходит через физический ethernet, то с суммой все в порядке и tcpdump пишет [udp sum ok].

В принципе, логично, что если пакет не передается через внешнюю физическую среду с помехами, смысла считать и проверять контрольную сумму нет. Где-то в описаниях сетевого драйвера xen как раз читал, что он контрольные суммы не считает, чтобы зря не терять времени.

По RFC, UDP checksum не обязательно вычислять вообще, и приложение может само решать, использовать ее или нет. Если ядро получило пакет без checksum, просто передает его приложению. Если checksum есть и неправильная, ядро должно отбросить пакет.

В линуксе есть socket option SO_NO_CHECK, которая отключает вычисление контрольной суммы при передаче. Ее использует, например, asterisk. Но сама опция в документации намерено скрыта:
————

* From: "Andi Kleen" * Date: Mon, 30 Aug 2010 00:26:51 +0200 (CEST) > In the source of the socket.7 man page, there is a comment: > > [[ > .\" don't document it because it can do too much harm. > .\".B SO_NO_CHECK > > ]] . On Linux UDP checksums are essentially free and there's no reason to turn them off and it would disable another safety line. That is why I didn't document the option.

Хотя при локальных передачах контрольная сумма не вычисляется, при чтении пакета целиком, например, через raw socket, поле контрольной суммы не является пустым, как это было бы при отключенной контрольной сумме. Вероятно, оно занято старым значением области памяти и поэтому ненулевое.

Это приводит к редким граблям, когда dhclient отказывается принимать DHCP Reply, отправленный через обычный UDP-сокет и проходящий через xen vif, аргументируя это неправильной контрольной суммой. В линуксе dhclient работает как раз (7) packet. Чтобы клиент не страдал из-за неправильной суммы, dhcpd приходится самостоятельно собирать и отправлять IP-пакет, досчитывая контрольную сумму UDP в приложении.

Источник

How to Disable UDP Checksum Validation in Linux

I recently needed to disable the validation of UDP checksums of incoming packets on a Linux machine for a security project. To my surprise, there weren’t any satisfactory solutions that I could easily find online related to this. The top Google results suggest disabling checksum offloading, which doesn’t disable checksum validation. Another result mentions a solution from within application source code, which you may not have access to or be able to modify.

In the end, I managed to figure this problem out and found that it’s usually possible without recompiling the kernel.

Читайте также:  Cmake gui linux install

In this post, I’ll describe how to set up a Linux machine to ignore UDP checksums in received packets. The mentioned steps may also be adapted to allow for disabling TCP checksum checking.

Check If Your Machine Can Receive Packets with Broken UDP Checksums#

Firstly, we need to check if your machine can already accept packets with invalid UDP checksums. This is necessary as your machine might already be able to receive them, but applications that are then passed the packets could be discarding them. Verifying this is also necessary to check if your network is capable of receiving packets with broken UDP checksums; there could be firewalls in place that verify packets before they reach your machine, in which case those will need to be reconfigured first.

Testing if your machine can already receive packets with broken checksums is straightforward — send packets with broken UDP checksums from one machine (source machine) to the machine that you want to disable UDP checksum validation on (destination machine), and check the traffic using tcpdump . I’ll outline how I’ve done this below.

    Run tcpdump on the destination machine, listening to internet traffic at the port that you expect to receive packets with broken UDP checksums on:

sudo tcpdump -i dst port -vv 
sudo ethtool --offload tx off 
bad_packet = IP(dst='') / UDP() / DNS(rd=1, qd=DNSQR(qname="www.example.com")) 

What If My Machine Doesn’t Receive Packets with Invalid UDP Checksums?#

A router between your machines could discard the packet due to an incorrect UDP checksum. Such an issue can be hard to diagnose, so it may be circumvented by sending packets from another machine.

If the packet is still not received, the kernel may be rejecting packets with invalid UDP checksums. In such case, the udp_recvmsg() function in the kernel would need to be modified to not return errors when the checksum validation fails. The kernel would then need to be recompiled — this can differ slightly between Linux distros, but many include useful documentation on how to achieve this (such as this for Ubuntu).

Note that changes to the kernel were not needed on the three machines that I have tested this on (Ubuntu 18.04 in Microsoft Azure, Ubuntu 20.10 in DigitalOcean, and Arch Linux with kernel version 5.11.11) but your mileage may vary.

Ignoring UDP checksums with nftables#

So far, we’ve confirmed that packets with broken UDP checksums can be received by our machine. However, these packets won’t get accepted by any target applications due to the invalid checksum. We can fix this using nftables .

We can configure nftables rules that set the UDP checksum of received packets to 0 before they’re passed to any applications. Packets with UDP checksums of 0 will not have their checksums validated, effectively disabling UDP checksum validation.

Читайте также:  Управление вентиляторами компьютера linux

To set this up, first install nftables with your favourite package manager. Next, add the following nftables rule:

sudo nft add table input_table sudo nft 'add chain input_table input ' sudo nft 'add rule input_table input ip protocol udp udp checksum set 0' 

This rule will set the UDP checksum of every received IP UDP packet to 0, which applications won’t validate.

Your machine will now ignore UDP checksums of received packets! Feel free to test this using Scapy.

To make the rule persistent across reboots, I’d recommend following the advice in this short guide to nftables .

Ignoring UDP Checksums Using Socket Options#

If you have the source code of the application that you want to send the packets with broken UDP checksums to, it may be possible by using socket options. To do so, the SO_NO_CHECK option would need to be declared with the UDP socket file descriptor, as described here.

Источник

How to enable UDP checksums

I’m working on a project involving UDP socket communication between a VxWorks device and a Linux machine. In this project, I’d like to take advantage of the checksum field of the UDP header. It appears that in the VxWorks socket interface, the checksum field of outgoing UDP packets is enabled by default. However, for the usual Unix sockets interface, there doesn’t appear to be any flag or other method to open a UDP socket that will check the checksum for incoming packets and populate it for outgoing ones. For the usual Unix sockets interface, does such a flag exist? Thanks!

If it doesn’t generate or check the UDP checksum, then it isn’t UDP, but something else. Unless you’ve read in the official docs that vxworks does not check the UDP checksums, it’s safe to assume that it does.

@nos UDP protocol specifies that checksum field can have value 0, and that means checksum was not generated, and so receiver should not try to check checksum.

@nos its OS implementation dependent. UDP packet without checksum is also valid packet. It is upto receive application.

3 Answers 3

I’m no expert, but the only thing that man 7 udp has to say on the matter suggests that it’s enabled by default:

UDP generates and checks checksums to catch transmission errors.

It does not mention any way to disable it.

Edit: I’m too lazy to look up current kernel source, but this page suggests that packets with invalid checksums are simply dropped (the csum_copy_err part).

With UDP over IPv4, the checksum field is technically optional. If the value is 0, checksums are ignored. However, UDP over IPv6 requires the checksum to be non-zero, and datagrams with a zeroed checksum must be discarded. If the checksum should be zero, it has to be sent as FFFF. (Look for «UDP checksum» in RFC 2460, the RFC that specifies IPv6).

Читайте также:  Где был создан linux

(I am not an expert. The following may be completely wrong.)

The network interface (or driver or something equivalent) should be checking the checksums of incoming packets. A checksum of all-bits-zero means «The outgoing interface didn’t generate a checksum.» The interface MUST check any other checksum (including all-bits-one, a.k.a. «negative zero» in the ones’ complement encoding used by the checksum field) and MUST drop the packet if it fails the check.

Therefore, you are never allowed to disable UDP checksum checking on incoming packets (if those packets have checksums provided, that is). That’s just a mandatory part of the UDP standard.

The receiving interface MAY drop packets with no checksum, [1] or MAY pass them on to the application (or MAY let the application configure its desired behavior, although if this is possible, I don’t know how to do it).

The only thing you might possibly be able to control is whether the sending interface generates checksums on outgoing packets. It’ll be platform-specific. I’ve collected some ways below, which might or might not work; caveat lector.

If you just take your platform’s default behavior, you will get UDP checksum generation by default — I’d put money on it.

[1] — RFC 8085: «An application is permitted to optionally discard UDP datagrams with a zero checksum [RFC1122].»

This comp.protocols.tcp-ip post from 1999 suggests that on Solaris, you can globally disable the generation of UDP checksums on outgoing packets via ndd at the command line:

ndd -set /dev/udp udp_do_checksum 0 

The ndd utility is specific to the Solaris kernel, and does not exist on Linux or FreeBSD. Also, even the Solaris docs say:

udp_do_checksum This parameter controls whether UDP calculates the checksum on outgoing UDP/IPv4 packets. Default 1 (enabled) When to Change Do not change this parameter. 

(On Linux and FreeBSD, /dev/udp «doesn’t really exist»; it’s a fiction provided by Bash. I don’t know whether /dev/udp «really exists» on Solaris.)

Microsoft’s docs imply that on Windows, you can disable UDP checksum generation programmatically on a per-socket basis, using a documented option:

DWORD trueValue = 1; int rc = setsockopt(fd, IPPROTO_UDP, UDP_NOCHECKSUM, (const char*)&yes, sizeof yes); if (rc != 0)

This thread implies that on FreeBSD (e.g. Mac OS X) you can disable checksum generation programmatically on a per-socket basis, using an otherwise undocumented (but present as of January 2018) option:

int yes = 1; int rc = setsockopt(sock, IPPROTO_UDP, UDP_NOCKSUM, (void*)&yes, sizeof yes); if (rc != 0)

And finally, this thread implies that on Linux you can disable checksum generation programmatically on a per-socket basis, using an otherwise undocumented (but present as of January 2018) option:

int yes = 1; int rc = setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, (void*)&yes, sizeof yes); if (rc != 0)

Источник

Оцените статью
Adblock
detector