[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220115040050.187972-1-kevmitch@arista.com>
Date: Fri, 14 Jan 2022 20:00:49 -0800
From: Kevin Mitchell <kevmitch@...sta.com>
To: unlisted-recipients:; (no To-header on input)
Cc: kevmitch@...sta.com, Pablo Neira Ayuso <pablo@...filter.org>,
Jozsef Kadlecsik <kadlec@...filter.org>,
Florian Westphal <fw@...len.de>,
"David S. Miller" <davem@...emloft.net>,
Jakub Kicinski <kuba@...nel.org>,
netfilter-devel@...r.kernel.org, coreteam@...filter.org,
netdev@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH 0/1] UDP traceroute packets with no checksum
We have run into some trouble with third-party devices whose traceroute
implementation sends UDP packets with empty checksums. Since the
checksum is optional for UDP inside an IPv4 packet, this is perfectly
legal, even if slightly strange. However, we found that such a packet
ends up getting silently ignored by our switch instead of eliciting the
expected ICMP response. The reason is that we handle UDP traceroute
packets are with the iptables rule
-A INPUT -p udp -m udp --dport 33434:33636 -j REJECT --reject-with icmp-port-unreachable
Such packets therefore get an iptables reject normally eliciting the
desired ICMP_DEST_UNREACH response from nf_send_unreach(). However, it
seems that before sending the ICMP response, this function determines
whether it needs to verify the checksum on the incoming packet by
checking if skb->ip_summed == CHECKSUM_UNNECESSARY or
skb->csum_valid. If this is not the case, then it proceeds to verify the
checksum. However, no provision is made here for an empty checksum,
which of course will fail to verify. In this case, netfilter declines
to send the ICMP response on the assumption that the packet is garbage
and the source address cannot be trusted.
As our front panel ports do not perform layer 4 hardware checksum
verification before sending packets to the kernel, the struct skb passed
to netif_recieve_skb by the driver are unconditionally marked
CHECKSUM_NONE.
The udp_error function makes accommodation for UDP packets with empty
checksum by declining to run nf_checksum on them and instead indicating
the packet acceptable. Since nf_checksum already alters the
skb->ip_summed member by marking it as CHECKSUM_COMPLETE when there is a
checksum to verify, it seems reasonable that udp_error similarly mark it
as CHECKSUM_UNNECESSARY when it determines there is no checksum. This is
supported by the note in skbuff.h that explicitly suggests such a value
for packets with empty checksum.
It seems that this issue was almost fixed by 7fc38225363d ("netfilter:
reject: skip csum verification for protocols that don't support it"),
which addressed protocols other than UDP. I considered adding a
IPPROTO_UDP branch to the nf_reject_verify_csum switch statement,
however it would necessarily be more complex than all of the existing
cases since it would require extracting the UDP header and checking the
checksum value. I'm open to doing that as well if requested, but it
doesn't appear to be necessary from what I can tell with the simpler
one-liner I have proposed here.
Finally, I have made no attempt to distinguish between IPv4 and IPv6 in
spite of the fact that empty checksums are not strictly allowed for UDP
inside IPv6. However, this decision to be more permissive appears to
have already been made since udp_error already declared such packets
error free. The aforementioned skbuff.h comment also explicitly mentions
setting empty checksum UDP in IPv6 as CHECKSUM_UNNECESSARY.
Powered by blists - more mailing lists