commit
f89abfb4068d31f7279cae298abf25e0c077d2d3 upstream.
There are two mechanisms to update the UDP checksum field:
1) _CSUM_TYPE and _CSUM_OFFSET which specify the type of checksum
(e.g. inet) and offset where it is located.
2) use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag to use layer 4 kernel
protocol parser.
The problem with 1) is that it is inconditional, that is, csum_type and
csum_offset cannot deal with zero UDP checksum.
Use NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag instead since it relies on the
layer 4 kernel parser which skips updating zero UDP checksum.
Extend test coverage for the UDP mangling with and without zero
checksum.
Fixes: e6c9174e13b2 ("proto: add checksum key information to struct proto_desc")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
}
if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
payload_needs_l4csum_update_pseudohdr(expr, desc)) ||
+ (expr->payload.base == PROTO_BASE_TRANSPORT_HDR && desc &&
+ desc == &proto_udp) ||
expr->payload.base == PROTO_BASE_INNER_HDR)
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
.name = "udp",
.id = PROTO_DESC_UDP,
.base = PROTO_BASE_TRANSPORT_HDR,
- .checksum_key = UDPHDR_CHECKSUM,
- .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
[UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),