diff options
author | ae <ae@FreeBSD.org> | 2014-11-05 09:23:29 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2014-11-05 09:23:29 +0000 |
commit | 6933957ccb7c9d3685e51d3aae7e3a8ab8d91c8f (patch) | |
tree | 4c59a543f83db7eb244721ea9d542127873cf105 /sys/netinet6/ip6_output.c | |
parent | f5ef39c5536cbd1ec407ea4507e695db17fe32c1 (diff) | |
download | FreeBSD-src-6933957ccb7c9d3685e51d3aae7e3a8ab8d91c8f.zip FreeBSD-src-6933957ccb7c9d3685e51d3aae7e3a8ab8d91c8f.tar.gz |
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 <interface> 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
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r-- | sys/netinet6/ip6_output.c | 178 |
1 files changed, 7 insertions, 171 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index b1d27d4..fe720ad 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -184,7 +184,7 @@ static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int); }\ } 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_pktopts *opt, 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_pktopts *opt, * 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_pktopts *opt, 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_pktopts *opt, 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: |