Message ID | 20230419075300.452227-3-steffen.klassert@secunet.com (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [1/2] xfrm: Remove inner/outer modes from input path | expand |
Hi Steffen, Herbert, > @@ -875,21 +875,10 @@ static int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb) > > static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) > { > - const struct xfrm_mode *inner_mode; > - > - if (x->sel.family == AF_UNSPEC) > - inner_mode = xfrm_ip2inner_mode(x, > - xfrm_af2proto(skb_dst(skb)->ops->family)); > - else > - inner_mode = &x->inner_mode; > - > - if (inner_mode == NULL) > - return -EAFNOSUPPORT; > - > - switch (inner_mode->family) { > - case AF_INET: > + switch (skb->protocol) { > + case htons(ETH_P_IP): > return xfrm4_extract_output(x, skb); > - case AF_INET6: > + case htons(ETH_P_IPV6): > return xfrm6_extract_output(x, skb); > } The changes in this function indirectly break tunneling IPv4 packets sent from RAW sockets. Such packets currently don't have skb->protocol set, so this results in EAFNOSUPPORT. For IPv6, this isn't a problem because the protocol is set since v3.11, or more specifically 9c9c9ad5fae7 ("ipv6: set skb->protocol on tcp, raw and ip6_append_data genereated skbs"). For IPv4, that's not the case. I wonder why this hasn't been an issue so far (e.g. with MTU calculation as mentioned in that commit for IPv6). To fix this, we basically need the patch below. The question is how it should be marked with regards to a Fixes: tag. Should it actually reference this xfrm-specific commit? Or should it even get backported further (e.g. reference the ipv6 commit above)? (The question then would be if this change could have unintended side-effects.) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 27da9d7294c0..696e1e734729 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -350,6 +350,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, goto error; skb_reserve(skb, hlen); + skb->protocol = htons(ETH_P_IP); skb->priority = READ_ONCE(sk->sk_priority); skb->mark = sockc->mark; skb->tstamp = sockc->transmit_time; Regards, Tobias
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index ff114d68cc43..369e5de8558f 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -412,7 +412,7 @@ static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; skb->protocol = htons(ETH_P_IP); - switch (x->outer_mode.encap) { + switch (x->props.mode) { case XFRM_MODE_BEET: return xfrm4_beet_encap_add(x, skb); case XFRM_MODE_TUNNEL: @@ -435,7 +435,7 @@ static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) skb->ignore_df = 1; skb->protocol = htons(ETH_P_IPV6); - switch (x->outer_mode.encap) { + switch (x->props.mode) { case XFRM_MODE_BEET: return xfrm6_beet_encap_add(x, skb); case XFRM_MODE_TUNNEL: @@ -451,22 +451,22 @@ static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb) { - switch (x->outer_mode.encap) { + switch (x->props.mode) { case XFRM_MODE_BEET: case XFRM_MODE_TUNNEL: - if (x->outer_mode.family == AF_INET) + if (x->props.family == AF_INET) return xfrm4_prepare_output(x, skb); - if (x->outer_mode.family == AF_INET6) + if (x->props.family == AF_INET6) return xfrm6_prepare_output(x, skb); break; case XFRM_MODE_TRANSPORT: - if (x->outer_mode.family == AF_INET) + if (x->props.family == AF_INET) return xfrm4_transport_output(x, skb); - if (x->outer_mode.family == AF_INET6) + if (x->props.family == AF_INET6) return xfrm6_transport_output(x, skb); break; case XFRM_MODE_ROUTEOPTIMIZATION: - if (x->outer_mode.family == AF_INET6) + if (x->props.family == AF_INET6) return xfrm6_ro_output(x, skb); WARN_ON_ONCE(1); break; @@ -875,21 +875,10 @@ static int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb) static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) { - const struct xfrm_mode *inner_mode; - - if (x->sel.family == AF_UNSPEC) - inner_mode = xfrm_ip2inner_mode(x, - xfrm_af2proto(skb_dst(skb)->ops->family)); - else - inner_mode = &x->inner_mode; - - if (inner_mode == NULL) - return -EAFNOSUPPORT; - - switch (inner_mode->family) { - case AF_INET: + switch (skb->protocol) { + case htons(ETH_P_IP): return xfrm4_extract_output(x, skb); - case AF_INET6: + case htons(ETH_P_IPV6): return xfrm6_extract_output(x, skb); }