svn commit: r308875 - projects/ipsec/sys/netinet
Andrey V. Elsukov
ae at FreeBSD.org
Sun Nov 20 09:04:18 UTC 2016
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
More information about the svn-src-projects
mailing list