svn commit: r308864 - projects/ipsec/sys/netinet6
Andrey V. Elsukov
ae at FreeBSD.org
Sat Nov 19 19:59:30 UTC 2016
Author: ae
Date: Sat Nov 19 19:59:28 2016
New Revision: 308864
URL: https://svnweb.freebsd.org/changeset/base/308864
Log:
Add ip6_ipsec_forward() function and call it from ip6_forward().
This function is inteded to check inbound and outbound security policies
for forwarded packet. If inbound policy doesn't discard packet, then we
check outbound policy. Since we act as router, we can apply only tunnel
mode IPsec to forwarded traffic (with transport mode we will not receive
responces from partner). So, if matched outbound policy has tunnel mode
transform, we can handle packet with IPsec. And this packet will be
consumed by ipsec6_process_packet(). Thus all logic related to IPsec
and MTU calculation in ip6_forward() is just dead code.
Remove ip[6]_ipsec_fwd() and all code with deep IPsec knowledge logic
from ip6_forward(). Use ip6_ipsec_forward() instead.
Also add IPSEC_FORWARD() wrapper macro.
Modified:
projects/ipsec/sys/netinet6/ip6_forward.c
projects/ipsec/sys/netinet6/ip6_ipsec.c
projects/ipsec/sys/netinet6/ip6_ipsec.h
Modified: projects/ipsec/sys/netinet6/ip6_forward.c
==============================================================================
--- projects/ipsec/sys/netinet6/ip6_forward.c Sat Nov 19 19:25:38 2016 (r308863)
+++ projects/ipsec/sys/netinet6/ip6_forward.c Sat Nov 19 19:59:28 2016 (r308864)
@@ -71,9 +71,6 @@ __FBSDID("$FreeBSD$");
#ifdef IPSEC
#include <netinet6/ip6_ipsec.h>
-#include <netipsec/ipsec.h>
-#include <netipsec/ipsec6.h>
-#include <netipsec/key.h>
#endif /* IPSEC */
/*
@@ -100,9 +97,6 @@ ip6_forward(struct mbuf *m, int srcrt)
struct ifnet *origifp; /* maybe unnecessary */
u_int32_t inzone, outzone;
struct in6_addr src_in6, dst_in6, odst;
-#ifdef IPSEC
- struct secpolicy *sp = NULL;
-#endif
struct m_tag *fwd_tag;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -130,32 +124,17 @@ ip6_forward(struct mbuf *m, int srcrt)
m_freem(m);
return;
}
-#ifdef IPSEC
- /*
- * Check if this packet has an active SA and needs to be dropped
- * instead of forwarded.
- */
- if (ip6_ipsec_fwd(m) != 0) {
- IP6STAT_INC(ip6s_cantforward);
- m_freem(m);
- return;
- }
-#endif /* IPSEC */
+ if (
#ifdef IPSTEALTH
- if (!V_ip6stealth) {
+ V_ip6stealth == 0 &&
#endif
- if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
+ ip6->ip6_hlim <= IPV6_HLIMDEC) {
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
icmp6_error(m, ICMP6_TIME_EXCEEDED,
- ICMP6_TIME_EXCEED_TRANSIT, 0);
+ ICMP6_TIME_EXCEED_TRANSIT, 0);
return;
}
- ip6->ip6_hlim -= IPV6_HLIMDEC;
-
-#ifdef IPSTEALTH
- }
-#endif
/*
* Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
@@ -168,167 +147,27 @@ ip6_forward(struct mbuf *m, int srcrt)
*/
mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
M_NOWAIT);
-
-#ifdef IPSEC
- /* get a security policy for this packet */
- sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, &error);
- if (sp == NULL) {
- IPSEC6STAT_INC(ips_out_inval);
- IP6STAT_INC(ip6s_cantforward);
- if (mcopy) {
-#if 0
- /* XXX: what icmp ? */
-#else
- m_freem(mcopy);
+#ifdef IPSTEALTH
+ if (V_ip6stealth == 0)
#endif
- }
- m_freem(m);
- return;
- }
+ ip6->ip6_hlim -= IPV6_HLIMDEC;
- error = 0;
-
- /* check policy */
- switch (sp->policy) {
- case IPSEC_POLICY_DISCARD:
- /*
- * This packet is just discarded.
- */
- IPSEC6STAT_INC(ips_out_polvio);
- IP6STAT_INC(ip6s_cantforward);
- KEY_FREESP(&sp);
- if (mcopy) {
-#if 0
- /* XXX: what icmp ? */
-#else
- m_freem(mcopy);
-#endif
- }
- m_freem(m);
+#ifdef IPSEC
+ if (IPSEC_FORWARD(ipv6, m, &error) != 0) {
+ /* mbuf consumed by IPsec */
+ m_freem(mcopy);
return;
-
- case IPSEC_POLICY_BYPASS:
- case IPSEC_POLICY_NONE:
- /* no need to do IPsec. */
- KEY_FREESP(&sp);
- goto skip_ipsec;
-
- case IPSEC_POLICY_IPSEC:
- if (sp->req == NULL) {
- /* XXX should be panic ? */
- printf("ip6_forward: No IPsec request specified.\n");
- IP6STAT_INC(ip6s_cantforward);
- KEY_FREESP(&sp);
- if (mcopy) {
-#if 0
- /* XXX: what icmp ? */
-#else
- m_freem(mcopy);
-#endif
- }
- m_freem(m);
- return;
- }
- /* do IPsec */
- break;
-
- case IPSEC_POLICY_ENTRUST:
- default:
- /* should be panic ?? */
- printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
- KEY_FREESP(&sp);
- goto skip_ipsec;
}
-
- {
- struct ipsecrequest *isr = NULL;
-
- /*
- * when the kernel forwards a packet, it is not proper to apply
- * IPsec transport mode to the packet. This check avoid from this.
- * at present, if there is even a transport mode SA request in the
- * security policy, the kernel does not apply IPsec to the packet.
- * this check is not enough because the following case is valid.
- * ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
- */
- for (isr = sp->req; isr; isr = isr->next) {
- if (isr->saidx.mode == IPSEC_MODE_ANY)
- goto doipsectunnel;
- if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
- goto doipsectunnel;
- }
-
- /*
- * if there's no need for tunnel mode IPsec, skip.
- */
- if (!isr)
- goto skip_ipsec;
-
- doipsectunnel:
- /*
- * All the extension headers will become inaccessible
- * (since they can be encrypted).
- * Don't panic, we need no more updates to extension headers
- * on inner IPv6 packet (since they are now encapsulated).
- *
- * IPv6 [ESP|AH] IPv6 [extension headers] payload
- */
-
/*
- * If we need to encapsulate the packet, do it here
- * ipsec6_proces_packet will send the packet using ip6_output
+ * mbuf wasn't consumed by IPsec, check error code.
*/
- error = ipsec6_process_packet(m, sp->req);
- /* Release SP if an error occurred */
- if (error != 0)
- KEY_FREESP(&sp);
- if (error == EJUSTRETURN) {
- /*
- * We had a SP with a level of 'use' and no SA. We
- * will just continue to process the packet without
- * IPsec processing.
- */
- error = 0;
- goto skip_ipsec;
- }
-
- if (error) {
- /* mbuf is already reclaimed in ipsec6_process_packet. */
- switch (error) {
- case EHOSTUNREACH:
- case ENETUNREACH:
- case EMSGSIZE:
- case ENOBUFS:
- case ENOMEM:
- break;
- default:
- printf("ip6_output (ipsec): error code %d\n", error);
- /* FALLTHROUGH */
- case ENOENT:
- /* don't show these error codes to the user */
- break;
- }
+ if (error != 0) {
IP6STAT_INC(ip6s_cantforward);
- if (mcopy) {
-#if 0
- /* XXX: what icmp ? */
-#else
- m_freem(mcopy);
-#endif
- }
+ m_freem(mcopy);
+ m_freem(m);
return;
- } else {
- /*
- * In the FAST IPSec case we have already
- * re-injected the packet and it has been freed
- * by the ipsec_done() function. So, just clean
- * up after ourselves.
- */
- m = NULL;
- goto freecopy;
}
- }
-skip_ipsec:
+ /* No IPsec processing required */
#endif
again:
bzero(&rin6, sizeof(struct route_in6));
@@ -540,34 +379,9 @@ pass:
/* See if the size was changed by the packet filter. */
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
- if (mcopy) {
- u_long mtu;
-#ifdef IPSEC
- size_t ipsechdrsiz;
-#endif /* IPSEC */
-
- mtu = IN6_LINKMTU(rt->rt_ifp);
-#ifdef IPSEC
- /*
- * When we do IPsec tunnel ingress, we need to play
- * with the link value (decrement IPsec header size
- * from mtu value). The code is much simpler than v4
- * case, as we have the outgoing interface for
- * encapsulated packet as "rt->rt_ifp".
- */
- ipsechdrsiz = ipsec_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND,
- NULL);
- if (ipsechdrsiz < mtu)
- mtu -= ipsechdrsiz;
- /*
- * if mtu becomes less than minimum MTU,
- * tell minimum MTU (and I'll need to fragment it).
- */
- if (mtu < IPV6_MMTU)
- mtu = IPV6_MMTU;
-#endif /* IPSEC */
- icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
- }
+ if (mcopy)
+ icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
+ IN6_LINKMTU(rt->rt_ifp));
goto bad;
}
Modified: projects/ipsec/sys/netinet6/ip6_ipsec.c
==============================================================================
--- projects/ipsec/sys/netinet6/ip6_ipsec.c Sat Nov 19 19:25:38 2016 (r308863)
+++ projects/ipsec/sys/netinet6/ip6_ipsec.c Sat Nov 19 19:59:28 2016 (r308864)
@@ -106,19 +106,6 @@ ip6_ipsec_filtertunnel(struct mbuf *m)
}
/*
- * Check if this packet has an active SA and needs to be dropped instead
- * of forwarded.
- * Called from ip6_forward().
- * 1 = drop packet, 0 = forward packet.
- */
-int
-ip6_ipsec_fwd(struct mbuf *m)
-{
-
- return (ipsec6_in_reject(m, NULL));
-}
-
-/*
* Check if protocol type doesn't have a further header and do IPSEC
* decryption or reject right now. Protocols with further headers get
* their IPSEC treatment within the protocol specific processing.
@@ -221,53 +208,84 @@ ip6_ipsec_output(struct mbuf *m, struct
return (0);
}
-#if 0
/*
- * Compute the MTU for a forwarded packet that gets IPSEC encapsulated.
- * Called from ip_forward().
- * Returns MTU suggestion for ICMP needfrag reply.
+ * Called from ip6_forward().
+ * 1 = drop packet, 0 = forward packet.
*/
int
-ip6_ipsec_mtu(struct mbuf *m)
+ip6_ipsec_forward(struct mbuf *m, int *error)
{
- int mtu = 0;
+ struct secpolicy *sp;
+ int idx;
+
/*
- * If the packet is routed over IPsec tunnel, tell the
- * originator the tunnel MTU.
- * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
- * XXX quickhack!!!
- */
-#ifdef IPSEC
- struct secpolicy *sp = NULL;
- int ipsecerror;
- int ipsechdr;
- struct route *ro;
- sp = ipsec_getpolicybyaddr(m,
- IPSEC_DIR_OUTBOUND,
- IP_FORWARDING,
- &ipsecerror);
+ * Check if this packet has an active inbound SP and needs to be
+ * dropped instead of forwarded.
+ */
+ if (ipsec6_in_reject(m, NULL) != 0) {
+ *error = EACCES;
+ return (0);
+ }
+ /*
+ * Now check outbound SP.
+ */
+ sp = ipsec6_checkpolicy(m, NULL, error);
+ /*
+ * There are four return cases:
+ * sp != NULL apply IPsec policy
+ * sp == NULL, error == 0 no IPsec handling needed
+ * sp == NULL, error == -EINVAL discard packet w/o error
+ * sp == NULL, error != 0 discard packet, report error
+ */
if (sp != NULL) {
- /* count IPsec header size */
- ipsechdr = ipsec_hdrsiz(m, IPSEC_DIR_OUTBOUND, NULL);
-
/*
- * find the correct route for outer IPv4
- * header, compute tunnel MTU.
+ * We have SP with IPsec transform, but we should check that
+ * it has tunnel mode request, because we can't use transport
+ * mode when forwarding.
+ *
+ * RFC2473 says:
+ * "A tunnel IPv6 packet resulting from the encapsulation of
+ * an original packet is considered an IPv6 packet originating
+ * from the tunnel entry-point node."
+ * So, we don't need MTU checking, after IPsec processing
+ * we will just fragment it if needed.
*/
- if (sp->req != NULL &&
- sp->req->sav != NULL &&
- sp->req->sav->sah != NULL) {
- ro = &sp->req->sav->sah->route_cache.sa_route;
- if (ro->ro_rt && ro->ro_rt->rt_ifp) {
- mtu = ro->ro_rt->rt_mtu ? ro->ro_rt->rt_mtu :
- ro->ro_rt->rt_ifp->if_mtu;
- mtu -= ipsechdr;
- }
+ for (idx = 0; idx < sp->tcount; idx++) {
+ if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL)
+ break;
+ }
+ if (idx == sp->tcount) {
+ *error = EACCES;
+ IPSEC6STAT_INC(ips_out_inval);
+ key_freesp(&sp);
+ return (0);
}
- KEY_FREESP(&sp);
+ /* NB: callee frees mbuf and releases reference to SP */
+ *error = ipsec6_process_packet(m, sp, NULL);
+ if (*error == EJUSTRETURN) {
+ /*
+ * We had a SP with a level of 'use' and no SA. We
+ * will just continue to process the packet without
+ * IPsec processing and return without error.
+ */
+ *error = 0;
+ return (0);
+ }
+ return (1); /* mbuf consumed by IPsec */
+ } else { /* sp == NULL */
+ if (*error != 0) {
+ /*
+ * Hack: -EINVAL is used to signal that a packet
+ * should be silently discarded. This is typically
+ * because we asked key management for an SA and
+ * it was delayed (e.g. kicked up to IKE).
+ */
+ if (*error == -EINVAL)
+ *error = 0;
+ m_freem(m);
+ return (1);
+ }
+ /* No IPsec processing for this packet. */
}
-#endif /* IPSEC */
- /* XXX else case missing. */
- return mtu;
+ return (0);
}
-#endif
Modified: projects/ipsec/sys/netinet6/ip6_ipsec.h
==============================================================================
--- projects/ipsec/sys/netinet6/ip6_ipsec.h Sat Nov 19 19:25:38 2016 (r308863)
+++ projects/ipsec/sys/netinet6/ip6_ipsec.h Sat Nov 19 19:59:28 2016 (r308864)
@@ -32,13 +32,11 @@
#ifndef _NETINET_IP6_IPSEC_H_
#define _NETINET_IP6_IPSEC_H_
+#define IPSEC_FORWARD(sc, m, perr) ip6_ipsec_forward((m), (perr))
#define IPSEC_OUTPUT(sc, m, inp, perr) ip6_ipsec_output((m), (inp), (perr))
int ip6_ipsec_filtertunnel(struct mbuf *);
-int ip6_ipsec_fwd(struct mbuf *);
int ip6_ipsec_input(struct mbuf *, int);
+int ip6_ipsec_forward(struct mbuf *, int *);
int ip6_ipsec_output(struct mbuf *, struct inpcb *, int *);
-#if 0
-int ip6_ipsec_mtu(struct mbuf *);
-#endif
#endif
More information about the svn-src-projects
mailing list