From owner-svn-src-stable-10@FreeBSD.ORG Wed Nov 5 09:23:32 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id E399C5D1; Wed, 5 Nov 2014 09:23:31 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::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 CE3D0AB2; Wed, 5 Nov 2014 09:23:31 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sA59NVsf055678; Wed, 5 Nov 2014 09:23:31 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sA59NTjY055666; Wed, 5 Nov 2014 09:23:29 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201411050923.sA59NTjY055666@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Wed, 5 Nov 2014 09:23:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r274132 - in stable/10/sys: netinet6 netipsec X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Nov 2014 09:23:32 -0000 Author: ae Date: Wed Nov 5 09:23:29 2014 New Revision: 274132 URL: https://svnweb.freebsd.org/changeset/base/274132 Log: MFC r266800 by vanhu: IPv4-in-IPv6 and IPv6-in-IPv4 IPsec tunnels. For IPv6-in-IPv4, you may need to do the following command on the tunnel interface if it is configured as IPv4 only: ifconfig inet6 -ifdisabled Code logic inspired from NetBSD. PR: kern/169438 MC r266822 by bz: Use IPv4 statistics in ipsec4_process_packet() rather than the IPv6 version. This also unbreaks the NOINET6 builds after r266800. MFC r268083 by zec: The assumption in ipsec4_process_packet() that the payload may be only IPv4 is wrong, so check the IP version before mangling the payload header. MFC r272394: Do not strip outer header when operating in transport mode. Instead requeue mbuf back to IPv4 protocol handler. If there is one extra IP-IP encapsulation, it will be handled with tunneling interface. And thus proper interface will be exposed into mbuf's rcvif. Also, tcpdump that listens on tunneling interface will see packets in both directions. PR: 194761 Modified: stable/10/sys/netinet6/ip6_forward.c stable/10/sys/netinet6/ip6_ipsec.c stable/10/sys/netinet6/ip6_ipsec.h stable/10/sys/netinet6/ip6_output.c stable/10/sys/netinet6/ip6_var.h stable/10/sys/netipsec/ipsec6.h stable/10/sys/netipsec/ipsec_input.c stable/10/sys/netipsec/ipsec_output.c stable/10/sys/netipsec/xform_ipip.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/netinet6/ip6_forward.c ============================================================================== --- stable/10/sys/netinet6/ip6_forward.c Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netinet6/ip6_forward.c Wed Nov 5 09:23:29 2014 (r274132) @@ -251,7 +251,6 @@ ip6_forward(struct mbuf *m, int srcrt) { struct ipsecrequest *isr = NULL; - struct ipsec_output_state state; /* * when the kernel forwards a packet, it is not proper to apply @@ -284,18 +283,27 @@ ip6_forward(struct mbuf *m, int srcrt) * * IPv6 [ESP|AH] IPv6 [extension headers] payload */ - bzero(&state, sizeof(state)); - state.m = m; - state.ro = NULL; /* update at ipsec6_output_tunnel() */ - state.dst = NULL; /* update at ipsec6_output_tunnel() */ - error = ipsec6_output_tunnel(&state, sp, 0); + /* + * If we need to encapsulate the packet, do it here + * ipsec6_proces_packet will send the packet using ip6_output + */ + error = ipsec6_process_packet(m, sp->req); - m = state.m; 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_output_tunnel. */ + /* mbuf is already reclaimed in ipsec6_process_packet. */ switch (error) { case EHOSTUNREACH: case ENETUNREACH: @@ -318,7 +326,6 @@ ip6_forward(struct mbuf *m, int srcrt) m_freem(mcopy); #endif } - m_freem(m); return; } else { /* @@ -330,25 +337,7 @@ ip6_forward(struct mbuf *m, int srcrt) m = NULL; goto freecopy; } - - if ((m != NULL) && (ip6 != mtod(m, struct ip6_hdr *)) ){ - /* - * now tunnel mode headers are added. we are originating - * packet instead of forwarding the packet. - */ - ip6_output(m, NULL, NULL, IPV6_FORWARDING/*XXX*/, NULL, NULL, - NULL); - goto freecopy; - } - - /* adjust pointer */ - dst = (struct sockaddr_in6 *)state.dst; - rt = state.ro ? state.ro->ro_rt : NULL; - if (dst != NULL && rt != NULL) - ipsecrt = 1; } - if (ipsecrt) - goto skip_routing; skip_ipsec: #endif again: @@ -371,9 +360,6 @@ again2: goto bad; } rt = rin6.ro_rt; -#ifdef IPSEC -skip_routing: -#endif /* * Source scope check: if a packet can't be delivered to its Modified: stable/10/sys/netinet6/ip6_ipsec.c ============================================================================== --- stable/10/sys/netinet6/ip6_ipsec.c Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netinet6/ip6_ipsec.c Wed Nov 5 09:23:29 2014 (r274132) @@ -220,23 +220,22 @@ ip6_ipsec_input(struct mbuf *m, int nxt) int ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, - struct ifnet **ifp, struct secpolicy **sp) + struct ifnet **ifp) { #ifdef IPSEC + struct secpolicy *sp = NULL; struct tdb_ident *tdbi; struct m_tag *mtag; /* XXX int s; */ - if (sp == NULL) - return 1; mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); if (mtag != NULL) { tdbi = (struct tdb_ident *)(mtag + 1); - *sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); - if (*sp == NULL) + sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); + if (sp == NULL) *error = -EINVAL; /* force silent drop */ m_tag_delete(*m, mtag); } else { - *sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, + sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, error, inp); } @@ -247,9 +246,9 @@ ip6_ipsec_output(struct mbuf **m, struct * sp == NULL, error == -EINVAL discard packet w/o error * sp == NULL, error != 0 discard packet, report error */ - if (*sp != NULL) { + if (sp != NULL) { /* Loop detection, check if ipsec processing already done */ - KASSERT((*sp)->req != NULL, ("ip_output: no ipsec request")); + KASSERT(sp->req != NULL, ("ip_output: no ipsec request")); for (mtag = m_tag_first(*m); mtag != NULL; mtag = m_tag_next(*m, mtag)) { if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) @@ -263,12 +262,12 @@ ip6_ipsec_output(struct mbuf **m, struct * an SA; e.g. on first reference. If it occurs, * then we let ipsec4_process_packet do its thing. */ - if ((*sp)->req->sav == NULL) + if (sp->req->sav == NULL) break; tdbi = (struct tdb_ident *)(mtag + 1); - if (tdbi->spi == (*sp)->req->sav->spi && - tdbi->proto == (*sp)->req->sav->sah->saidx.proto && - bcmp(&tdbi->dst, &(*sp)->req->sav->sah->saidx.dst, + if (tdbi->spi == sp->req->sav->spi && + tdbi->proto == sp->req->sav->sah->saidx.proto && + bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst, sizeof (union sockaddr_union)) == 0) { /* * No IPsec processing is needed, free @@ -277,7 +276,7 @@ ip6_ipsec_output(struct mbuf **m, struct * NB: null pointer to avoid free at * done: below. */ - KEY_FREESP(sp), *sp = NULL; + KEY_FREESP(&sp), sp = NULL; goto done; } } @@ -285,16 +284,37 @@ ip6_ipsec_output(struct mbuf **m, struct /* * Do delayed checksums now because we send before * this is done in the normal processing path. - * For IPv6 we do delayed checksums in ip6_output.c. */ #ifdef INET if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - ipseclog((LOG_DEBUG, - "%s: we do not support IPv4 over IPv6", __func__)); in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } #endif + if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { + in6_delayed_cksum(*m, (*m)->m_pkthdr.len - sizeof(struct ip6_hdr), + sizeof(struct ip6_hdr)); + (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; + } +#ifdef SCTP + if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { + sctp_delayed_cksum(*m, sizeof(struct ip6_hdr)); + (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; + } +#endif + + /* NB: callee frees mbuf */ + *error = ipsec6_process_packet(*m, sp->req); + + 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 done; + } /* * Preserve KAME behaviour: ENOENT can be returned @@ -305,7 +325,7 @@ ip6_ipsec_output(struct mbuf **m, struct */ if (*error == ENOENT) *error = 0; - goto do_ipsec; + goto reinjected; } else { /* sp == NULL */ if (*error != 0) { /* @@ -322,10 +342,16 @@ ip6_ipsec_output(struct mbuf **m, struct } } done: + if (sp != NULL) + KEY_FREESP(&sp); return 0; -do_ipsec: +reinjected: + if (sp != NULL) + KEY_FREESP(&sp); return -1; bad: + if (sp != NULL) + KEY_FREESP(&sp); return 1; #endif /* IPSEC */ return 0; Modified: stable/10/sys/netinet6/ip6_ipsec.h ============================================================================== --- stable/10/sys/netinet6/ip6_ipsec.h Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netinet6/ip6_ipsec.h Wed Nov 5 09:23:29 2014 (r274132) @@ -36,7 +36,7 @@ int ip6_ipsec_filtertunnel(struct mbuf * int ip6_ipsec_fwd(struct mbuf *); int ip6_ipsec_input(struct mbuf *, int); int ip6_ipsec_output(struct mbuf **, struct inpcb *, int *, int *, - struct ifnet **, struct secpolicy **sp); + struct ifnet **); #if 0 int ip6_ipsec_mtu(struct mbuf *); #endif Modified: stable/10/sys/netinet6/ip6_output.c ============================================================================== --- stable/10/sys/netinet6/ip6_output.c Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netinet6/ip6_output.c Wed Nov 5 09:23:29 2014 (r274132) @@ -184,7 +184,7 @@ static int copypktopts(struct ip6_pktopt }\ } while (/*CONSTCOND*/ 0) -static void +void in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset) { u_short csum; @@ -248,15 +248,7 @@ ip6_output(struct mbuf *m0, struct ip6_p u_int32_t zone; struct route_in6 *ro_pmtu = NULL; int hdrsplit = 0; - int needipsec = 0; int sw_csum, tso; -#ifdef IPSEC - struct ipsec_output_state state; - struct ip6_rthdr *rh = NULL; - int needipsectun = 0; - int segleft_org = 0; - struct secpolicy *sp = NULL; -#endif /* IPSEC */ struct m_tag *fwd_tag = NULL; ip6 = mtod(m, struct ip6_hdr *); @@ -298,26 +290,12 @@ ip6_output(struct mbuf *m0, struct ip6_p * IPSec checking which handles several cases. * FAST IPSEC: We re-injected the packet. */ - switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp, &sp)) + switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp)) { case 1: /* Bad packet */ goto freehdrs; - case -1: /* Do IPSec */ - needipsec = 1; - /* - * Do delayed checksums now, as we may send before returning. - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { - plen = m->m_pkthdr.len - sizeof(*ip6); - in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr)); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; - } -#ifdef SCTP - if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { - sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); - m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; - } -#endif + case -1: /* IPSec done */ + goto done; case 0: /* No IPSec */ default: break; @@ -337,15 +315,15 @@ ip6_output(struct mbuf *m0, struct ip6_p optlen += exthdrs.ip6e_rthdr->m_len; unfragpartlen = optlen + sizeof(struct ip6_hdr); - /* NOTE: we don't add AH/ESP length here. do that later. */ + /* NOTE: we don't add AH/ESP length here (done in ip6_ipsec_output) */ if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len; /* - * If we need IPsec, or there is at least one extension header, + * If there is at least one extension header, * separate IP6 header from the payload. */ - if ((needipsec || optlen) && !hdrsplit) { + if (optlen && !hdrsplit) { if ((error = ip6_splithdr(m, &exthdrs)) != 0) { m = NULL; goto freehdrs; @@ -420,72 +398,6 @@ ip6_output(struct mbuf *m0, struct ip6_p MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, IPPROTO_ROUTING); -#ifdef IPSEC - if (!needipsec) - goto skip_ipsec2; - - /* - * pointers after IPsec headers are not valid any more. - * other pointers need a great care too. - * (IPsec routines should not mangle mbufs prior to AH/ESP) - */ - exthdrs.ip6e_dest2 = NULL; - - if (exthdrs.ip6e_rthdr) { - rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); - segleft_org = rh->ip6r_segleft; - rh->ip6r_segleft = 0; - } - - bzero(&state, sizeof(state)); - state.m = m; - error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, - &needipsectun); - m = state.m; - 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. - */ - ; - } else if (error) { - /* mbuf is already reclaimed in ipsec6_output_trans. */ - m = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("[%s:%d] (ipsec): error code %d\n", - __func__, __LINE__, error); - /* FALLTHROUGH */ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; - } - goto bad; - } else if (!needipsectun) { - /* - * 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 done; - } - if (exthdrs.ip6e_rthdr) { - /* ah6_output doesn't modify mbuf chain */ - rh->ip6r_segleft = segleft_org; - } -skip_ipsec2:; -#endif /* IPSEC */ - /* * If there is a routing header, discard the packet. */ @@ -551,77 +463,6 @@ again: ip6->ip6_hlim = V_ip6_defmcasthlim; } -#ifdef IPSEC - /* - * We may re-inject packets into the stack here. - */ - if (needipsec && needipsectun) { - struct ipsec_output_state state; - - /* - * 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 - */ - bzero(&exthdrs, sizeof(exthdrs)); - exthdrs.ip6e_ip6 = m; - - bzero(&state, sizeof(state)); - state.m = m; - state.ro = (struct route *)ro; - state.dst = (struct sockaddr *)dst; - - error = ipsec6_output_tunnel(&state, sp, flags); - - m = state.m; - ro = (struct route_in6 *)state.ro; - dst = (struct sockaddr_in6 *)state.dst; - 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. - */ - ; - } else if (error) { - /* mbuf is already reclaimed in ipsec6_output_tunnel. */ - m0 = m = NULL; - m = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("[%s:%d] (ipsec): error code %d\n", - __func__, __LINE__, error); - /* FALLTHROUGH */ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; - } - goto bad; - } 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 done; - } - - exthdrs.ip6e_ip6 = m; - } -#endif /* IPSEC */ - /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); @@ -1182,11 +1023,6 @@ done: RO_RTFREE(ro); if (ro_pmtu == &ip6route) RO_RTFREE(ro_pmtu); -#ifdef IPSEC - if (sp != NULL) - KEY_FREESP(&sp); -#endif - return (error); freehdrs: Modified: stable/10/sys/netinet6/ip6_var.h ============================================================================== --- stable/10/sys/netinet6/ip6_var.h Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netinet6/ip6_var.h Wed Nov 5 09:23:29 2014 (r274132) @@ -456,6 +456,7 @@ int in6_selectroute_fib(struct sockaddr_ struct rtentry **, u_int); u_int32_t ip6_randomid(void); u_int32_t ip6_randomflowlabel(void); +void in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset); #endif /* _KERNEL */ #endif /* !_NETINET6_IP6_VAR_H_ */ Modified: stable/10/sys/netipsec/ipsec6.h ============================================================================== --- stable/10/sys/netipsec/ipsec6.h Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netipsec/ipsec6.h Wed Nov 5 09:23:29 2014 (r274132) @@ -76,6 +76,7 @@ extern int ipsec6_output_trans __P((stru struct mbuf *, struct secpolicy *, int, int *)); extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, struct secpolicy *, int)); +extern int ipsec6_process_packet(struct mbuf *, struct ipsecrequest *); #endif /*_KERNEL*/ #endif /*_NETIPSEC_IPSEC6_H_*/ Modified: stable/10/sys/netipsec/ipsec_input.c ============================================================================== --- stable/10/sys/netipsec/ipsec_input.c Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netipsec/ipsec_input.c Wed Nov 5 09:23:29 2014 (r274132) @@ -295,7 +295,7 @@ int ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff, struct m_tag *mt) { - int prot, af, sproto; + int prot, af, sproto, isr_prot; struct ip *ip; struct m_tag *mtag; struct tdb_ident *tdbi; @@ -349,20 +349,34 @@ ipsec4_common_input_cb(struct mbuf *m, s } prot = ip->ip_p; -#ifdef notyet +#ifdef DEV_ENC + encif->if_ipackets++; + encif->if_ibytes += m->m_pkthdr.len; + + /* + * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP + * packet later after it has been decapsulated. + */ + ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE); + + if (prot != IPPROTO_IPIP) + if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) + return (error); +#endif /* DEV_ENC */ + /* IP-in-IP encapsulation */ - if (prot == IPPROTO_IPIP) { - struct ip ipn; + if (prot == IPPROTO_IPIP && + saidx->mode != IPSEC_MODE_TRANSPORT) { if (m->m_pkthdr.len - skip < sizeof(struct ip)) { IPSEC_ISTAT(sproto, hdrops); error = EINVAL; goto bad; } - /* ipn will now contain the inner IPv4 header */ - m_copydata(m, ip->ip_hl << 2, sizeof(struct ip), - (caddr_t) &ipn); + /* enc0: strip outer IPv4 header */ + m_striphdr(m, 0, ip->ip_hl << 2); +#ifdef notyet /* XXX PROXY address isn't recorded in SAH */ /* * Check that the inner source address is the same as @@ -388,21 +402,21 @@ ipsec4_common_input_cb(struct mbuf *m, s error = EACCES; goto bad; } +#endif /* notyet */ } #ifdef INET6 /* IPv6-in-IP encapsulation. */ - if (prot == IPPROTO_IPV6) { - struct ip6_hdr ip6n; + if (prot == IPPROTO_IPV6 && + saidx->mode != IPSEC_MODE_TRANSPORT) { if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { IPSEC_ISTAT(sproto, hdrops); error = EINVAL; goto bad; } - /* ip6n will now contain the inner IPv6 header. */ - m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr), - (caddr_t) &ip6n); - + /* enc0: strip IPv4 header, keep IPv6 header only */ + m_striphdr(m, 0, ip->ip_hl << 2); +#ifdef notyet /* * Check that the inner source address is the same as * the proxy address, if available. @@ -426,9 +440,9 @@ ipsec4_common_input_cb(struct mbuf *m, s error = EACCES; goto bad; } +#endif /* notyet */ } #endif /* INET6 */ -#endif /*XXX*/ /* * Record what we've done to the packet (under what SA it was @@ -464,25 +478,50 @@ ipsec4_common_input_cb(struct mbuf *m, s key_sa_recordxfer(sav, m); /* record data transfer */ + /* + * In transport mode requeue decrypted mbuf back to IPv4 protocol + * handler. This is necessary to correctly expose rcvif. + */ + if (saidx->mode == IPSEC_MODE_TRANSPORT) + prot = IPPROTO_IPIP; #ifdef DEV_ENC - encif->if_ipackets++; - encif->if_ibytes += m->m_pkthdr.len; - /* - * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP - * packet later after it has been decapsulated. + * Pass the mbuf to enc0 for bpf and pfil. */ - ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE); - - if (prot != IPPROTO_IPIP) - if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) - return (error); + if (prot == IPPROTO_IPIP) + ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_AFTER); +#ifdef INET6 + if (prot == IPPROTO_IPV6) + ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_AFTER); #endif + if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0) + return (error); +#endif /* DEV_ENC */ + /* * Re-dispatch via software interrupt. */ - if ((error = netisr_queue_src(NETISR_IP, (uintptr_t)sav->spi, m))) { + + switch (prot) { + case IPPROTO_IPIP: + isr_prot = NETISR_IP; + break; +#ifdef INET6 + case IPPROTO_IPV6: + isr_prot = NETISR_IPV6; + break; +#endif + default: + DPRINTF(("%s: cannot handle inner ip proto %d\n", + __func__, prot)); + IPSEC_ISTAT(sproto, nopf); + error = EPFNOSUPPORT; + goto bad; + } + + error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m); + if (error) { IPSEC_ISTAT(sproto, qfull); DPRINTF(("%s: queue full; proto %u packet dropped\n", __func__, sproto)); @@ -605,20 +644,34 @@ ipsec6_common_input_cb(struct mbuf *m, s prot = 0; m_copydata(m, protoff, 1, (unsigned char *) &prot); -#ifdef notyet +#ifdef DEV_ENC + encif->if_ipackets++; + encif->if_ibytes += m->m_pkthdr.len; + + /* + * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP + * packet later after it has been decapsulated. + */ + ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_BEFORE); + + /* XXX-BZ does not make sense. */ + if (prot != IPPROTO_IPIP) + if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) + return (error); +#endif /* DEV_ENC */ + #ifdef INET /* IP-in-IP encapsulation */ if (prot == IPPROTO_IPIP) { - struct ip ipn; - if (m->m_pkthdr.len - skip < sizeof(struct ip)) { IPSEC_ISTAT(sproto, hdrops); error = EINVAL; goto bad; } /* ipn will now contain the inner IPv4 header */ - m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn); - + m_striphdr(m, 0, skip); + skip = 0; +#ifdef notyet /* * Check that the inner source address is the same as * the proxy address, if available. @@ -641,22 +694,20 @@ ipsec6_common_input_cb(struct mbuf *m, s error = EACCES; goto bad; } +#endif /* notyet */ } #endif /* INET */ - /* IPv6-in-IP encapsulation */ if (prot == IPPROTO_IPV6) { - struct ip6_hdr ip6n; - if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) { IPSEC_ISTAT(sproto, hdrops); error = EINVAL; goto bad; } /* ip6n will now contain the inner IPv6 header. */ - m_copydata(m, skip, sizeof(struct ip6_hdr), - (caddr_t) &ip6n); - + m_striphdr(m, 0, skip); + skip = 0; +#ifdef notyet /* * Check that the inner source address is the same as * the proxy address, if available. @@ -680,8 +731,8 @@ ipsec6_common_input_cb(struct mbuf *m, s error = EACCES; goto bad; } +#endif /* notyet */ } -#endif /*XXX*/ /* * Record what we've done to the packet (under what SA it was @@ -719,23 +770,22 @@ ipsec6_common_input_cb(struct mbuf *m, s key_sa_recordxfer(sav, m); #ifdef DEV_ENC - encif->if_ipackets++; - encif->if_ibytes += m->m_pkthdr.len; - /* - * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP - * packet later after it has been decapsulated. + * Pass the mbuf to enc0 for bpf and pfil. */ - ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_BEFORE); - - /* XXX-BZ does not make sense. */ - if (prot != IPPROTO_IPIP) - if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0) - return (error); +#ifdef INET + if (prot == IPPROTO_IPIP) + ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_AFTER); #endif + if (prot == IPPROTO_IPV6) + ipsec_bpf(m, sav, AF_INET6, ENC_IN|ENC_AFTER); + if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0) + return (error); +#endif /* DEV_ENC */ /* Retrieve new protocol */ - m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8); + /* We have stripped the IP6 header from the mbuf, we have to use the backuped proto value instead */ + nxt8 = prot; /* * See the end of ip6_input for this logic. Modified: stable/10/sys/netipsec/ipsec_output.c ============================================================================== --- stable/10/sys/netipsec/ipsec_output.c Wed Nov 5 08:10:58 2014 (r274131) +++ stable/10/sys/netipsec/ipsec_output.c Wed Nov 5 09:23:29 2014 (r274132) @@ -176,8 +176,7 @@ ipsec_process_done(struct mbuf *m, struc #ifdef INET6 case AF_INET6: /* XXX */ - ipsec6_output_trans() - ipsec6_output_tunnel() + return ipsec6_process_packet(m, isr->next); /* NOTREACHED */ #endif /* INET6 */ #endif @@ -498,9 +497,11 @@ ipsec4_process_packet( goto bad; } ip = mtod(m, struct ip *); - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + if (ip->ip_v == IPVERSION) { + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + } /* Encapsulate the packet */ error = ipip_output(m, isr, &mp, 0, 0); @@ -542,7 +543,7 @@ ipsec4_process_packet( #ifdef DEV_ENC /* pass the mbuf to enc0 for bpf processing */ - ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_AFTER); + ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER); /* pass the mbuf to enc0 for packet filtering */ if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) goto bad; @@ -559,9 +560,26 @@ ipsec4_process_packet( * for reclaiming their resources. */ if (sav->tdb_xform->xf_type != XF_IP4) { - ip = mtod(m, struct ip *); - i = ip->ip_hl << 2; - off = offsetof(struct ip, ip_p); + union sockaddr_union *dst = &sav->sah->saidx.dst; + switch(dst->sa.sa_family) { + case AF_INET: + ip = mtod(m, struct ip *); + i = ip->ip_hl << 2; + off = offsetof(struct ip, ip_p); + break; +#ifdef INET6 + case AF_INET6: + i = sizeof(struct ip6_hdr); + off = offsetof(struct ip6_hdr, ip6_nxt); + break; +#endif /* INET6 */ + default: + DPRINTF(("%s: unsupported protocol family %u\n", + __func__, dst->sa.sa_family)); + error = EPFNOSUPPORT; + IPSECSTAT_INC(ips_out_inval); + goto bad; + } error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); } else { error = ipsec_process_done(m, isr); @@ -577,224 +595,50 @@ bad: } #endif -#ifdef INET6 -/* - * Chop IP6 header from the payload. - */ -static struct mbuf * -ipsec6_splithdr(struct mbuf *m) -{ - struct mbuf *mh; - struct ip6_hdr *ip6; - int hlen; - - IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr), - ("first mbuf too short, len %u", m->m_len)); - ip6 = mtod(m, struct ip6_hdr *); - hlen = sizeof(struct ip6_hdr); - if (m->m_len > hlen) { - MGETHDR(mh, M_NOWAIT, MT_DATA); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} - -/* - * IPsec output logic for IPv6, transport mode. - */ -int -ipsec6_output_trans( - struct ipsec_output_state *state, - u_char *nexthdrp, - struct mbuf *mprev, - struct secpolicy *sp, - int flags, - int *tun) -{ - struct ipsecrequest *isr; - struct secasindex saidx; - int error = 0; - struct mbuf *m; - - IPSEC_ASSERT(state != NULL, ("null state")); - IPSEC_ASSERT(state->m != NULL, ("null m")); - IPSEC_ASSERT(nexthdrp != NULL, ("null nexthdrp")); - IPSEC_ASSERT(mprev != NULL, ("null mprev")); - IPSEC_ASSERT(sp != NULL, ("null sp")); - IPSEC_ASSERT(tun != NULL, ("null tun")); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("%s: applied SP\n", __func__); - kdebug_secpolicy(sp)); - - isr = sp->req; - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* the rest will be handled by ipsec6_output_tunnel() */ - *tun = 1; /* need tunnel-mode processing */ - return 0; - } - - *tun = 0; - m = state->m; - - IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ - isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); - if (isr == NULL) { - if (error != 0) { -#ifdef notdef - /* XXX should notification be done for all errors ? */ - /* - * Notify the fact that the packet is discarded - * to ourselves. I believe this is better than - * just silently discarding. (jinmei@kame.net) - * XXX: should we restrict the error to TCP packets? - * XXX: should we directly notify sockets via - * pfctlinputs? - */ - icmp6_error(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADMIN, 0); - m = NULL; /* NB: icmp6_error frees mbuf */ -#endif - goto bad; - } - return EJUSTRETURN; - } - - error = (*isr->sav->tdb_xform->xf_output)(m, isr, NULL, - sizeof (struct ip6_hdr), - offsetof(struct ip6_hdr, - ip6_nxt)); - IPSECREQUEST_UNLOCK(isr); - return error; -bad: - if (isr) - IPSECREQUEST_UNLOCK(isr); - if (m) - m_freem(m); - state->m = NULL; - return error; -} +#ifdef INET6 static int -ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav) +in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) { - struct ip6_hdr *oip6; - struct ip6_hdr *ip6; - size_t plen; + struct in6_addr ia2; - /* can't tunnel between different AFs */ - if (sav->sah->saidx.src.sa.sa_family != AF_INET6 || - sav->sah->saidx.dst.sa.sa_family != AF_INET6) { - m_freem(m); - return EINVAL; - } - IPSEC_ASSERT(m->m_len == sizeof (struct ip6_hdr), - ("mbuf wrong size; len %u", m->m_len)); - - - /* - * grow the mbuf to accomodate the new IPv6 header. - */ - plen = m->m_pkthdr.len; - if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) { - struct mbuf *n; - MGET(n, M_NOWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = sizeof(struct ip6_hdr); - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(n, struct ip6_hdr *); - } else { - m->m_next->m_len += sizeof(struct ip6_hdr); - m->m_next->m_data -= sizeof(struct ip6_hdr); - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(m->m_next, struct ip6_hdr *); - } - ip6 = mtod(m, struct ip6_hdr *); - bcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr)); - - /* Fake link-local scope-class addresses */ - if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) - oip6->ip6_src.s6_addr16[1] = 0; - if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) - oip6->ip6_dst.s6_addr16[1] = 0; - - /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ - /* ECN consideration. */ - ip6_ecn_ingress(V_ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); - if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) - ip6->ip6_plen = htons(plen); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***