From owner-svn-src-projects@freebsd.org Sun Nov 20 09:04:18 2016 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 75472C48E95 for ; Sun, 20 Nov 2016 09:04:18 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 35F531351; Sun, 20 Nov 2016 09:04:18 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAK94HaV065357; Sun, 20 Nov 2016 09:04:17 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAK94Hhm065354; Sun, 20 Nov 2016 09:04:17 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201611200904.uAK94Hhm065354@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Sun, 20 Nov 2016 09:04:17 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r308875 - projects/ipsec/sys/netinet X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Nov 2016 09:04:18 -0000 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 #ifdef IPSEC #include -#include -#include #endif /* IPSEC */ #include @@ -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