From d583be6335a8fb3bda90b8d47b08ef3fc8686183 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 19 May 2023 10:23:22 +0300 Subject: [PATCH] bpf: nat: consistently use has_l4_header in IPv4 SNAT path We currently don't support IPv4 fragmentation in the SNAT path (or more precisely, we don't have support for loading the L4 ports of a fragment). But we already have two spots that correctly check whether the packet has a L4 header (or only requires L3 SNAT). Make this consistent across the whole flow, so that it also gets applied in the CT lookup. Passing this through to snat_v4_nat_handle_icmp_frag_needed() also avoids a revalidation of the outer header. Signed-off-by: Julian Wiedmann --- bpf/lib/nat.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/bpf/lib/nat.h b/bpf/lib/nat.h index 8d5e9dd1edd90..e5e6145bea8fc 100644 --- a/bpf/lib/nat.h +++ b/bpf/lib/nat.h @@ -938,7 +938,8 @@ static __always_inline bool snat_v4_prepare_state(struct __ctx_buff *ctx, } static __always_inline __maybe_unused int -snat_v4_nat_handle_icmp_frag_needed(struct __ctx_buff *ctx, __u64 off) +snat_v4_nat_handle_icmp_frag_needed(struct __ctx_buff *ctx, __u64 off, + bool has_l4_header) { struct ipv4_ct_tuple tuple = {}; struct ipv4_nat_entry *state; @@ -946,8 +947,6 @@ snat_v4_nat_handle_icmp_frag_needed(struct __ctx_buff *ctx, __u64 off) __u32 icmpoff = off + sizeof(struct icmphdr); __be16 identifier; __u8 type; - void *data, *data_end; - struct iphdr *ip4; int ret; /* According to the RFC 5508, any networking equipment that is @@ -1007,9 +1006,6 @@ snat_v4_nat_handle_icmp_frag_needed(struct __ctx_buff *ctx, __u64 off) if (IS_ERR(ret)) return ret; - if (!revalidate_data(ctx, &data, &data_end, - &ip4)) - return DROP_INVALID; /* Switch back to the outer header. */ tuple.nexthdr = IPPROTO_ICMP; /* Reset so no l4 NAT is done in snat_v4_rewrite_egress. We don't need @@ -1017,7 +1013,7 @@ snat_v4_nat_handle_icmp_frag_needed(struct __ctx_buff *ctx, __u64 off) */ tuple.sport = state->to_sport; - return snat_v4_rewrite_egress(ctx, &tuple, state, off, ipv4_has_l4_header(ip4)); + return snat_v4_rewrite_egress(ctx, &tuple, state, off, has_l4_header); } static __always_inline __maybe_unused int @@ -1033,7 +1029,7 @@ snat_v4_nat(struct __ctx_buff *ctx, const struct ipv4_nat_target *target, __s8 * __be16 dport; } l4hdr; bool icmp_echoreply = false; - bool has_l4_header = true; + bool has_l4_header; int ct_action = ACTION_UNSPEC; __u64 off; int ret; @@ -1044,6 +1040,7 @@ snat_v4_nat(struct __ctx_buff *ctx, const struct ipv4_nat_target *target, __s8 * return DROP_INVALID; snat_v4_init_tuple(ip4, NAT_DIR_EGRESS, &tuple); + has_l4_header = ipv4_has_l4_header(ip4); off = ((void *)ip4 - data) + ipv4_hdrlen(ip4); switch (tuple.nexthdr) { @@ -1076,7 +1073,7 @@ snat_v4_nat(struct __ctx_buff *ctx, const struct ipv4_nat_target *target, __s8 * case ICMP_DEST_UNREACH: if (icmphdr.code != ICMP_FRAG_NEEDED) return DROP_UNKNOWN_ICMP_CODE; - return snat_v4_nat_handle_icmp_frag_needed(ctx, off); + return snat_v4_nat_handle_icmp_frag_needed(ctx, off, has_l4_header); default: return DROP_NAT_UNSUPP_PROTO; } @@ -1094,7 +1091,7 @@ snat_v4_nat(struct __ctx_buff *ctx, const struct ipv4_nat_target *target, __s8 * if (ret < 0) return ret; - return snat_v4_rewrite_egress(ctx, &tuple, state, off, ipv4_has_l4_header(ip4)); + return snat_v4_rewrite_egress(ctx, &tuple, state, off, has_l4_header); } static __always_inline __maybe_unused int