Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Nov 2016 09:04:17 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r308875 - projects/ipsec/sys/netinet
Message-ID:  <201611200904.uAK94Hhm065354@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sun Nov 20 09:04:16 2016
New Revision: 308875
URL: https://svnweb.freebsd.org/changeset/base/308875

Log:
  Add ip_ipsec_forward() function and call it from ip_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 ipsec4_process_packet().
  
  In ip_forward() do IPsec handling after TTL decrementing. If mbuf will
  be consumed by IPsec, it will be encapsulated, thus its TTL value should
  be decremented before (RFC1853). Also by the same reason we need to make
  mbuf's copy before decrementing TTL and doing IPsec checks.
  
  Also add IPSEC_FORWARD() and IPSEC_INPUT() wrapper macros.

Modified:
  projects/ipsec/sys/netinet/ip_input.c
  projects/ipsec/sys/netinet/ip_ipsec.c
  projects/ipsec/sys/netinet/ip_ipsec.h

Modified: projects/ipsec/sys/netinet/ip_input.c
==============================================================================
--- projects/ipsec/sys/netinet/ip_input.c	Sun Nov 20 06:11:30 2016	(r308874)
+++ projects/ipsec/sys/netinet/ip_input.c	Sun Nov 20 09:04:16 2016	(r308875)
@@ -79,8 +79,6 @@ __FBSDID("$FreeBSD$");
 #include <netinet/ip_carp.h>
 #ifdef IPSEC
 #include <netinet/ip_ipsec.h>
-#include <netipsec/ipsec.h>
-#include <netipsec/key.h>
 #endif /* IPSEC */
 #include <netinet/in_rss.h>
 
@@ -797,7 +795,7 @@ ours:
 	 * note that we do not visit this with protocols with pcb layer
 	 * code - like udp/tcp/raw ip.
 	 */
-	if (ip_ipsec_input(m, ip->ip_p) != 0)
+	if (IPSEC_INPUT(ipv4, m, ip->ip_p) != 0)
 		goto bad;
 #endif /* IPSEC */
 
@@ -940,24 +938,14 @@ ip_forward(struct mbuf *m, int srcrt)
 		m_freem(m);
 		return;
 	}
-#ifdef IPSEC
-	if (ip_ipsec_fwd(m) != 0) {
-		IPSTAT_INC(ips_cantforward);
-		m_freem(m);
-		return;
-	}
-#endif /* IPSEC */
+	if (
 #ifdef IPSTEALTH
-	if (!V_ipstealth) {
+	    V_ipstealth == 0 &&
 #endif
-		if (ip->ip_ttl <= IPTTLDEC) {
-			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
-			    0, 0);
-			return;
-		}
-#ifdef IPSTEALTH
+	    ip->ip_ttl <= IPTTLDEC) {
+		icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, 0);
+		return;
 	}
-#endif
 
 	bzero(&ro, sizeof(ro));
 	sin = (struct sockaddr_in *)&ro.ro_dst;
@@ -976,19 +964,6 @@ ip_forward(struct mbuf *m, int srcrt)
 		ifa_ref(&ia->ia_ifa);
 	} else
 		ia = NULL;
-#ifndef IPSEC
-	/*
-	 * 'ia' may be NULL if there is no route for this destination.
-	 * In case of IPsec, Don't discard it just yet, but pass it to
-	 * ip_output in case of outgoing IPsec policy.
-	 */
-	if (!srcrt && ia == NULL) {
-		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
-		RO_RTFREE(&ro);
-		return;
-	}
-#endif
-
 	/*
 	 * Save the IP header and at most 8 bytes of the payload,
 	 * in case we need to generate an ICMP message to the src.
@@ -1021,15 +996,26 @@ ip_forward(struct mbuf *m, int srcrt)
 		mcopy->m_pkthdr.len = mcopy->m_len;
 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
 	}
-
 #ifdef IPSTEALTH
-	if (!V_ipstealth) {
+	if (V_ipstealth == 0)
 #endif
 		ip->ip_ttl -= IPTTLDEC;
-#ifdef IPSTEALTH
+#ifdef IPSEC
+	if (IPSEC_FORWARD(ipv4, m, &error) != 0) { /* mbuf consumed by IPsec */
+		m_freem(mcopy);
+		return;
 	}
-#endif
-
+	/*
+	 * mbuf wasn't consumed by IPsec, check error code.
+	 */
+	if (error != 0) {
+		IPSTAT_INC(ips_cantforward);
+		m_freem(m);
+		m_freem(mcopy);
+		return;
+	}
+	/* No IPsec processing required */
+#endif /* IPSEC */
 	/*
 	 * If forwarding packet using same interface that it came in on,
 	 * perhaps should send a redirect to sender to shortcut a hop.
@@ -1107,14 +1093,6 @@ ip_forward(struct mbuf *m, int srcrt)
 	case EMSGSIZE:
 		type = ICMP_UNREACH;
 		code = ICMP_UNREACH_NEEDFRAG;
-
-#ifdef IPSEC
-		/* 
-		 * If IPsec is configured for this path,
-		 * override any possibly mtu value set by ip_output.
-		 */ 
-		mtu = ip_ipsec_mtu(mcopy, mtu);
-#endif /* IPSEC */
 		/*
 		 * If the MTU was set before make sure we are below the
 		 * interface MTU.

Modified: projects/ipsec/sys/netinet/ip_ipsec.c
==============================================================================
--- projects/ipsec/sys/netinet/ip_ipsec.c	Sun Nov 20 06:11:30 2016	(r308874)
+++ projects/ipsec/sys/netinet/ip_ipsec.c	Sun Nov 20 09:04:16 2016	(r308875)
@@ -95,19 +95,6 @@ ip_ipsec_filtertunnel(struct mbuf *m)
 }
 
 /*
- * Check if this packet has an active SA and needs to be dropped instead
- * of forwarded.
- * Called from ip_forward().
- * 1 = drop packet, 0 = forward packet.
- */
-int
-ip_ipsec_fwd(struct mbuf *m)
-{
-
-	return (ipsec4_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.
@@ -220,3 +207,80 @@ ip_ipsec_output(struct mbuf *m, struct i
 	}
 	return (0);
 }
+
+/*
+ * Called from ip_forward().
+ * 1 = drop packet, 0 = forward packet.
+ */
+int
+ip_ipsec_forward(struct mbuf *m, int *error)
+{
+	struct secpolicy *sp;
+	int idx;
+
+	/*
+	 * Check if this packet has an active inbound SP and needs to be
+	 * dropped instead of forwarded.
+	 */
+	if (ipsec4_in_reject(m, NULL) != 0) {
+		*error = EACCES;
+		return (0);
+	}
+	/*
+	 * Now check outbound SP.
+	 */
+	sp = ipsec4_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) {
+		/*
+		 * 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.
+		 */
+		for (idx = 0; idx < sp->tcount; idx++) {
+			if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL)
+				break;
+		}
+		if (idx == sp->tcount) {
+			*error = EACCES;
+			IPSECSTAT_INC(ips_out_inval);
+			key_freesp(&sp);
+			return (0);
+		}
+		/* NB: callee frees mbuf and releases reference to SP */
+		*error = ipsec4_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. */
+	}
+	return (0);
+}
+
+

Modified: projects/ipsec/sys/netinet/ip_ipsec.h
==============================================================================
--- projects/ipsec/sys/netinet/ip_ipsec.h	Sun Nov 20 06:11:30 2016	(r308874)
+++ projects/ipsec/sys/netinet/ip_ipsec.h	Sun Nov 20 09:04:16 2016	(r308875)
@@ -32,11 +32,13 @@
 #ifndef _NETINET_IP_IPSEC_H_
 #define _NETINET_IP_IPSEC_H_
 
+#define	IPSEC_INPUT(sc, m, arg)		ip_ipsec_input((m), (arg))
+#define	IPSEC_FORWARD(sc, m, perr)	ip_ipsec_forward((m), (perr))
 #define	IPSEC_OUTPUT(sc, m, inp, perr)	ip_ipsec_output((m), (inp), (perr))
 
 int	ip_ipsec_filtertunnel(struct mbuf *);
-int	ip_ipsec_fwd(struct mbuf *);
 int	ip_ipsec_input(struct mbuf *, int);
 int	ip_ipsec_mtu(struct mbuf *, int);
+int	ip_ipsec_forward(struct mbuf *, int *);
 int	ip_ipsec_output(struct mbuf *, struct inpcb *, int *);
 #endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611200904.uAK94Hhm065354>