From a380976c585a18a3e103cf68105431c922872509 Mon Sep 17 00:00:00 2001 From: bluhm Date: Mon, 22 Nov 2021 13:47:10 +0000 Subject: [PATCH] Copy code from ip_forward() to ip6_forward() to fix Path MTU discovery in IPsec IPv6 tunnel. Implement sending ICMP6 packet too big messages. Also implement the pf error case in ip6_forward(). While there, do some cleanup and make the IPv4 and IPv6 code look similar. OK tobhe@ --- sys/netinet/ip_input.c | 34 ++++++++++++++++------------------ sys/netinet6/ip6_forward.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 3915225657e..9e7e20af30b 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.363 2021/06/21 22:09:14 jca Exp $ */ +/* $OpenBSD: ip_input.c,v 1.364 2021/11/22 13:47:10 bluhm Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -1436,7 +1436,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) struct ip *ip = mtod(m, struct ip *); struct sockaddr_in *sin; struct route ro; - int error, type = 0, code = 0, destmtu = 0, fake = 0, len; + int error = 0, type = 0, code = 0, destmtu = 0, fake = 0, len; u_int32_t dest; dest = 0; @@ -1535,29 +1535,17 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) goto freecopy; switch (error) { - case 0: /* forwarded, but need redirect */ /* type, code set above */ break; - case ENETUNREACH: /* shouldn't happen, checked above */ - case EHOSTUNREACH: - case ENETDOWN: - case EHOSTDOWN: - default: - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - break; - case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; - -#ifdef IPSEC if (rt != NULL) { - if (rt->rt_mtu) + if (rt->rt_mtu) { destmtu = rt->rt_mtu; - else { + } else { struct ifnet *destifp; destifp = if_get(rt->rt_ifidx); @@ -1566,8 +1554,9 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) if_put(destifp); } } -#endif /*IPSEC*/ ipstat_inc(ips_cantfrag); + if (destmtu == 0) + goto freecopy; break; case EACCES: @@ -1576,6 +1565,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) * packet back since pf(4) takes care of it. */ goto freecopy; + case ENOBUFS: /* * a router should not generate ICMP_SOURCEQUENCH as @@ -1584,8 +1574,16 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) * or the underlying interface is rate-limited. */ goto freecopy; - } + case ENETUNREACH: /* shouldn't happen, checked above */ + case EHOSTUNREACH: + case ENETDOWN: + case EHOSTDOWN: + default: + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + break; + } mcopy = m_copym(&mfake, 0, len, M_DONTWAIT); if (mcopy) icmp_error(mcopy, type, code, dest, destmtu); diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 12b74cb63b7..ba9c25e16d1 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.101 2021/10/14 17:39:42 bluhm Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.102 2021/11/22 13:47:10 bluhm Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -88,7 +88,7 @@ ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt) struct sockaddr_in6 *sin6; struct route_in6 ro; struct ifnet *ifp = NULL; - int error = 0, type = 0, code = 0; + int error = 0, type = 0, code = 0, destmtu = 0; struct mbuf *mcopy = NULL; #ifdef IPSEC struct tdb *tdb = NULL; @@ -340,6 +340,7 @@ senderr: #endif if (mcopy == NULL) goto out; + switch (error) { case 0: if (type == ND_REDIRECT) { @@ -349,7 +350,30 @@ senderr: goto freecopy; case EMSGSIZE: - /* xxx MTU is constant in PPP? */ + type = ICMP6_PACKET_TOO_BIG; + code = 0; + if (rt != NULL) { + if (rt->rt_mtu) { + destmtu = rt->rt_mtu; + } else { + struct ifnet *destifp; + + destifp = if_get(rt->rt_ifidx); + if (destifp != NULL) + destmtu = destifp->if_mtu; + if_put(destifp); + } + } + ip6stat_inc(ip6s_cantfrag); + if (destmtu == 0) + goto freecopy; + break; + + case EACCES: + /* + * pf(4) blocked the packet. There is no need to send an ICMP + * packet back since pf(4) takes care of it. + */ goto freecopy; case ENOBUFS: @@ -365,7 +389,7 @@ senderr: code = ICMP6_DST_UNREACH_ADDR; break; } - icmp6_error(mcopy, type, code, 0); + icmp6_error(mcopy, type, code, destmtu); goto out; freecopy: -- 2.20.1