ip6_ipsec.c revision 283901
144743Smarkm/*- 244743Smarkm * Copyright (c) 1982, 1986, 1988, 1993 344743Smarkm * The Regents of the University of California. All rights reserved. 444743Smarkm * 544743Smarkm * Redistribution and use in source and binary forms, with or without 644743Smarkm * modification, are permitted provided that the following conditions 744743Smarkm * are met: 844743Smarkm * 1. Redistributions of source code must retain the above copyright 944743Smarkm * notice, this list of conditions and the following disclaimer. 1044743Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1144743Smarkm * notice, this list of conditions and the following disclaimer in the 1244743Smarkm * documentation and/or other materials provided with the distribution. 1344743Smarkm * 4. Neither the name of the University nor the names of its contributors 1444743Smarkm * may be used to endorse or promote products derived from this software 1544743Smarkm * without specific prior written permission. 1644743Smarkm * 1744743Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1844743Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1944743Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2044743Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2144743Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2244743Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2344743Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2444743Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2544743Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2644743Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2744743Smarkm * SUCH DAMAGE. 2844743Smarkm */ 2944743Smarkm 3044743Smarkm#include <sys/cdefs.h> 3144743Smarkm__FBSDID("$FreeBSD: stable/10/sys/netinet6/ip6_ipsec.c 283901 2015-06-02 03:14:42Z ae $"); 3244743Smarkm 3344743Smarkm#include "opt_inet.h" 3444743Smarkm#include "opt_inet6.h" 3544743Smarkm#include "opt_ipsec.h" 3644743Smarkm 3744743Smarkm#include <sys/param.h> 3844743Smarkm#include <sys/systm.h> 3944743Smarkm#include <sys/kernel.h> 4044743Smarkm#include <sys/mac.h> 4144743Smarkm#include <sys/malloc.h> 4244743Smarkm#include <sys/mbuf.h> 4344743Smarkm#include <sys/protosw.h> 4444743Smarkm#include <sys/socket.h> 4544743Smarkm#include <sys/socketvar.h> 4644743Smarkm#include <sys/sysctl.h> 4744743Smarkm#include <sys/syslog.h> 4844743Smarkm 4944743Smarkm#include <net/if.h> 5044743Smarkm#include <net/vnet.h> 5144743Smarkm 5244743Smarkm#include <netinet/in.h> 5344743Smarkm#include <netinet/in_systm.h> 5444743Smarkm#include <netinet/in_var.h> 5544743Smarkm#include <netinet/ip.h> 5644743Smarkm#include <netinet/ip6.h> 5744743Smarkm#include <netinet/in_pcb.h> 5844743Smarkm#include <netinet/ip_var.h> 5944743Smarkm#include <netinet/ip_options.h> 6044743Smarkm 6144743Smarkm#include <machine/in_cksum.h> 6244743Smarkm 6344743Smarkm#ifdef IPSEC 6444743Smarkm#include <netipsec/ipsec.h> 6544743Smarkm#include <netipsec/ipsec6.h> 6644743Smarkm#include <netipsec/xform.h> 6744743Smarkm#include <netipsec/key.h> 6844743Smarkm#ifdef IPSEC_DEBUG 6944743Smarkm#include <netipsec/key_debug.h> 7044743Smarkm#else 7144743Smarkm#define KEYDEBUG(lev,arg) 7244743Smarkm#endif 7344743Smarkm#endif /*IPSEC*/ 7444743Smarkm 7544743Smarkm#include <netinet6/ip6_ipsec.h> 7644743Smarkm#include <netinet6/ip6_var.h> 7744743Smarkm 7844743Smarkmextern struct protosw inet6sw[]; 7944743Smarkm 8044743Smarkm 8144743Smarkm#ifdef INET6 8244743Smarkm#ifdef IPSEC 8344743Smarkm#ifdef IPSEC_FILTERTUNNEL 8444743Smarkmstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 1; 8544743Smarkm#else 8644743Smarkmstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 0; 8744743Smarkm#endif 8844743Smarkm#define V_ip6_ipsec6_filtertunnel VNET(ip6_ipsec6_filtertunnel) 8944743Smarkm 9044743SmarkmSYSCTL_DECL(_net_inet6_ipsec6); 9144743SmarkmSYSCTL_VNET_INT(_net_inet6_ipsec6, OID_AUTO, 9244743Smarkm filtertunnel, CTLFLAG_RW, &VNET_NAME(ip6_ipsec6_filtertunnel), 0, 9344743Smarkm "If set filter packets from an IPsec tunnel."); 9444743Smarkm#endif /* IPSEC */ 9544743Smarkm#endif /* INET6 */ 9644743Smarkm 9744743Smarkm/* 9844743Smarkm * Check if we have to jump over firewall processing for this packet. 9944743Smarkm * Called from ip6_input(). 10044743Smarkm * 1 = jump over firewall, 0 = packet goes through firewall. 10144743Smarkm */ 10244743Smarkmint 10344743Smarkmip6_ipsec_filtertunnel(struct mbuf *m) 10444743Smarkm{ 10544743Smarkm#ifdef IPSEC 10644743Smarkm 10744743Smarkm /* 10844743Smarkm * Bypass packet filtering for packets previously handled by IPsec. 10944743Smarkm */ 11044743Smarkm if (!V_ip6_ipsec6_filtertunnel && 11144743Smarkm m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 11244743Smarkm return 1; 11344743Smarkm#endif 11444743Smarkm return 0; 11544743Smarkm} 11644743Smarkm 11744743Smarkm/* 11844743Smarkm * Check if this packet has an active SA and needs to be dropped instead 11944743Smarkm * of forwarded. 12044743Smarkm * Called from ip6_input(). 12144743Smarkm * 1 = drop packet, 0 = forward packet. 12244743Smarkm */ 12344743Smarkmint 12444743Smarkmip6_ipsec_fwd(struct mbuf *m) 12544743Smarkm{ 12644743Smarkm#ifdef IPSEC 12744743Smarkm struct m_tag *mtag; 12844743Smarkm struct tdb_ident *tdbi; 12944743Smarkm struct secpolicy *sp; 13044743Smarkm int error; 13144743Smarkm mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 13244743Smarkm if (mtag != NULL) { 13344743Smarkm tdbi = (struct tdb_ident *)(mtag + 1); 13444743Smarkm sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 13544743Smarkm } else { 13644743Smarkm sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 13744743Smarkm IP_FORWARDING, &error); 13844743Smarkm } 13944743Smarkm if (sp == NULL) { /* NB: can happen if error */ 14044743Smarkm /*XXX error stat???*/ 14144743Smarkm DPRINTF(("%s: no SP for forwarding\n", __func__)); /*XXX*/ 14244743Smarkm return 1; 14344743Smarkm } 14444743Smarkm 14544743Smarkm /* 14644743Smarkm * Check security policy against packet attributes. 14744743Smarkm */ 14844743Smarkm error = ipsec_in_reject(sp, m); 14944743Smarkm KEY_FREESP(&sp); 15044743Smarkm if (error) { 15144743Smarkm IP6STAT_INC(ip6s_cantforward); 15244743Smarkm return 1; 15344743Smarkm } 15444743Smarkm#endif /* IPSEC */ 15544743Smarkm return 0; 15644743Smarkm} 15744743Smarkm 15844743Smarkm/* 15944743Smarkm * Check if protocol type doesn't have a further header and do IPSEC 16044743Smarkm * decryption or reject right now. Protocols with further headers get 16144743Smarkm * their IPSEC treatment within the protocol specific processing. 16244743Smarkm * Called from ip6_input(). 16344743Smarkm * 1 = drop packet, 0 = continue processing packet. 16444743Smarkm */ 16544743Smarkmint 16644743Smarkmip6_ipsec_input(struct mbuf *m, int nxt) 16744743Smarkm{ 16844743Smarkm#ifdef IPSEC 16944743Smarkm struct m_tag *mtag; 17044743Smarkm struct tdb_ident *tdbi; 17144743Smarkm struct secpolicy *sp; 17244743Smarkm int error; 17344743Smarkm /* 17444743Smarkm * enforce IPsec policy checking if we are seeing last header. 17544743Smarkm * note that we do not visit this with protocols with pcb layer 17644743Smarkm * code - like udp/tcp/raw ip. 17744743Smarkm */ 17844743Smarkm if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 17944743Smarkm ipsec6_in_reject(m, NULL)) { 18044743Smarkm 18144743Smarkm /* 18244743Smarkm * Check if the packet has already had IPsec processing 18344743Smarkm * done. If so, then just pass it along. This tag gets 18444743Smarkm * set during AH, ESP, etc. input handling, before the 18544743Smarkm * packet is returned to the ip input queue for delivery. 18644743Smarkm */ 18744743Smarkm mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 18844743Smarkm if (mtag != NULL) { 18944743Smarkm tdbi = (struct tdb_ident *)(mtag + 1); 19044743Smarkm sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 19144743Smarkm } else { 19244743Smarkm sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 19344743Smarkm IP_FORWARDING, &error); 19444743Smarkm } 19544743Smarkm if (sp != NULL) { 19644743Smarkm /* 19744743Smarkm * Check security policy against packet attributes. 19844743Smarkm */ 19944743Smarkm error = ipsec_in_reject(sp, m); 20044743Smarkm KEY_FREESP(&sp); 20144743Smarkm } else { 20244743Smarkm /* XXX error stat??? */ 20344743Smarkm error = EINVAL; 20444743Smarkm DPRINTF(("%s: no SP, packet discarded\n", __func__));/*XXX*/ 20544743Smarkm return 1; 20644743Smarkm } 20744743Smarkm if (error) 20844743Smarkm return 1; 20944743Smarkm } 21044743Smarkm#endif /* IPSEC */ 21144743Smarkm return 0; 21244743Smarkm} 21344743Smarkm 21444743Smarkm/* 21544743Smarkm * Called from ip6_output(). 21644743Smarkm * 1 = drop packet, 0 = continue processing packet, 21744743Smarkm * -1 = packet was reinjected and stop processing packet 21844743Smarkm */ 21944743Smarkm 22044743Smarkmint 22144743Smarkmip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, 22244743Smarkm struct ifnet **ifp) 22344743Smarkm{ 22444743Smarkm#ifdef IPSEC 22544743Smarkm struct secpolicy *sp = NULL; 22644743Smarkm struct tdb_ident *tdbi; 22744743Smarkm struct m_tag *mtag; 22844743Smarkm /* XXX int s; */ 22944743Smarkm mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); 23044743Smarkm if (mtag != NULL) { 23144743Smarkm tdbi = (struct tdb_ident *)(mtag + 1); 23244743Smarkm sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); 23344743Smarkm if (sp == NULL) 23444743Smarkm *error = -EINVAL; /* force silent drop */ 23544743Smarkm m_tag_delete(*m, mtag); 23644743Smarkm } else { 23744743Smarkm sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, 23844743Smarkm error, inp); 23944743Smarkm } 24044743Smarkm 24144743Smarkm /* 24244743Smarkm * There are four return cases: 24344743Smarkm * sp != NULL apply IPsec policy 24444743Smarkm * sp == NULL, error == 0 no IPsec handling needed 24544743Smarkm * sp == NULL, error == -EINVAL discard packet w/o error 24644743Smarkm * sp == NULL, error != 0 discard packet, report error 24744743Smarkm */ 24844743Smarkm if (sp != NULL) { 24944743Smarkm /* Loop detection, check if ipsec processing already done */ 25044743Smarkm KASSERT(sp->req != NULL, ("ip_output: no ipsec request")); 25144743Smarkm for (mtag = m_tag_first(*m); mtag != NULL; 25244743Smarkm mtag = m_tag_next(*m, mtag)) { 25344743Smarkm if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) 25444743Smarkm continue; 25544743Smarkm if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && 25644743Smarkm mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) 25744743Smarkm continue; 25844743Smarkm /* 25944743Smarkm * Check if policy has no SA associated with it. 26044743Smarkm * This can happen when an SP has yet to acquire 26144743Smarkm * an SA; e.g. on first reference. If it occurs, 26244743Smarkm * then we let ipsec4_process_packet do its thing. 26344743Smarkm */ 26444743Smarkm if (sp->req->sav == NULL) 26544743Smarkm break; 26644743Smarkm tdbi = (struct tdb_ident *)(mtag + 1); 26744743Smarkm if (tdbi->spi == sp->req->sav->spi && 26844743Smarkm tdbi->proto == sp->req->sav->sah->saidx.proto && 26944743Smarkm bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst, 27044743Smarkm sizeof (union sockaddr_union)) == 0) { 27144743Smarkm /* 27244743Smarkm * No IPsec processing is needed, free 27344743Smarkm * reference to SP. 27444743Smarkm */ 27544743Smarkm goto done; 27644743Smarkm } 27744743Smarkm } 27844743Smarkm 27944743Smarkm /* 28044743Smarkm * Do delayed checksums now because we send before 28144743Smarkm * this is done in the normal processing path. 28244743Smarkm */ 28344743Smarkm#ifdef INET 28444743Smarkm if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 28544743Smarkm in_delayed_cksum(*m); 28644743Smarkm (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 28744743Smarkm } 28844743Smarkm#endif 28944743Smarkm if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { 29044743Smarkm in6_delayed_cksum(*m, (*m)->m_pkthdr.len - sizeof(struct ip6_hdr), 29144743Smarkm sizeof(struct ip6_hdr)); 29244743Smarkm (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; 29344743Smarkm } 29444743Smarkm#ifdef SCTP 29544743Smarkm if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { 29644743Smarkm sctp_delayed_cksum(*m, sizeof(struct ip6_hdr)); 29744743Smarkm (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; 29844743Smarkm } 29944743Smarkm#endif 30044743Smarkm 30144743Smarkm /* NB: callee frees mbuf */ 30244743Smarkm *error = ipsec6_process_packet(*m, sp->req); 30344743Smarkm 30444743Smarkm if (*error == EJUSTRETURN) { 30544743Smarkm /* 30644743Smarkm * We had a SP with a level of 'use' and no SA. We 30744743Smarkm * will just continue to process the packet without 30844743Smarkm * IPsec processing. 30944743Smarkm */ 31044743Smarkm *error = 0; 31144743Smarkm goto done; 31244743Smarkm } 31344743Smarkm 31444743Smarkm /* 31544743Smarkm * Preserve KAME behaviour: ENOENT can be returned 31644743Smarkm * when an SA acquire is in progress. Don't propagate 31744743Smarkm * this to user-level; it confuses applications. 31844743Smarkm * 31944743Smarkm * XXX this will go away when the SADB is redone. 32044743Smarkm */ 32144743Smarkm if (*error == ENOENT) 32244743Smarkm *error = 0; 32344743Smarkm goto reinjected; 32444743Smarkm } else { /* sp == NULL */ 32544743Smarkm if (*error != 0) { 32644743Smarkm /* 32744743Smarkm * Hack: -EINVAL is used to signal that a packet 32844743Smarkm * should be silently discarded. This is typically 32944743Smarkm * because we asked key management for an SA and 33044743Smarkm * it was delayed (e.g. kicked up to IKE). 33144743Smarkm */ 33244743Smarkm if (*error == -EINVAL) 33344743Smarkm *error = 0; 33444743Smarkm goto bad; 33544743Smarkm } else { 33644743Smarkm /* No IPsec processing for this packet. */ 33744743Smarkm } 33844743Smarkm } 33944743Smarkmdone: 34044743Smarkm if (sp != NULL) 34144743Smarkm KEY_FREESP(&sp); 34244743Smarkm return 0; 34344743Smarkmreinjected: 34444743Smarkm if (sp != NULL) 34544743Smarkm KEY_FREESP(&sp); 34644743Smarkm return -1; 34744743Smarkmbad: 34844743Smarkm if (sp != NULL) 34944743Smarkm KEY_FREESP(&sp); 35044743Smarkm return 1; 35144743Smarkm#endif /* IPSEC */ 35244743Smarkm return 0; 35344743Smarkm} 35444743Smarkm 35544743Smarkm#if 0 35644743Smarkm/* 35744743Smarkm * Compute the MTU for a forwarded packet that gets IPSEC encapsulated. 35844743Smarkm * Called from ip_forward(). 35944743Smarkm * Returns MTU suggestion for ICMP needfrag reply. 36044743Smarkm */ 36144743Smarkmint 36244743Smarkmip6_ipsec_mtu(struct mbuf *m) 36344743Smarkm{ 36444743Smarkm int mtu = 0; 36544743Smarkm /* 36644743Smarkm * If the packet is routed over IPsec tunnel, tell the 36744743Smarkm * originator the tunnel MTU. 36844743Smarkm * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 36944743Smarkm * XXX quickhack!!! 37044743Smarkm */ 37144743Smarkm#ifdef IPSEC 37244743Smarkm struct secpolicy *sp = NULL; 37344743Smarkm int ipsecerror; 37444743Smarkm int ipsechdr; 37544743Smarkm struct route *ro; 37644743Smarkm sp = ipsec_getpolicybyaddr(m, 37744743Smarkm IPSEC_DIR_OUTBOUND, 37844743Smarkm IP_FORWARDING, 37944743Smarkm &ipsecerror); 38044743Smarkm if (sp != NULL) { 38144743Smarkm /* count IPsec header size */ 38244743Smarkm ipsechdr = ipsec_hdrsiz(m, IPSEC_DIR_OUTBOUND, NULL); 38344743Smarkm 38444743Smarkm /* 38544743Smarkm * find the correct route for outer IPv4 38644743Smarkm * header, compute tunnel MTU. 38744743Smarkm */ 38844743Smarkm if (sp->req != NULL && 38944743Smarkm sp->req->sav != NULL && 39044743Smarkm sp->req->sav->sah != NULL) { 39144743Smarkm ro = &sp->req->sav->sah->route_cache.sa_route; 39244743Smarkm if (ro->ro_rt && ro->ro_rt->rt_ifp) { 39344743Smarkm mtu = ro->ro_rt->rt_mtu ? ro->ro_rt->rt_mtu : 39444743Smarkm ro->ro_rt->rt_ifp->if_mtu; 39544743Smarkm mtu -= ipsechdr; 39644743Smarkm } 39744743Smarkm } 39844743Smarkm KEY_FREESP(&sp); 39944743Smarkm } 40044743Smarkm#endif /* IPSEC */ 40144743Smarkm /* XXX else case missing. */ 40244743Smarkm return mtu; 40344743Smarkm} 40444743Smarkm#endif 40544743Smarkm