ip6_ipsec.c revision 215701
160484Sobrien/*- 233965Sjdp * Copyright (c) 1982, 1986, 1988, 1993 360484Sobrien * The Regents of the University of California. All rights reserved. 438889Sjdp * 538889Sjdp * Redistribution and use in source and binary forms, with or without 638889Sjdp * modification, are permitted provided that the following conditions 733965Sjdp * are met: 838889Sjdp * 1. Redistributions of source code must retain the above copyright 938889Sjdp * notice, this list of conditions and the following disclaimer. 1038889Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1138889Sjdp * notice, this list of conditions and the following disclaimer in the 1233965Sjdp * documentation and/or other materials provided with the distribution. 1333965Sjdp * 4. Neither the name of the University nor the names of its contributors 1438889Sjdp * may be used to endorse or promote products derived from this software 1533965Sjdp * without specific prior written permission. 1638889Sjdp * 1738889Sjdp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1833965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1933965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2038889Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2133965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2233965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2338889Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2438889Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2538889Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2638889Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2738889Sjdp * SUCH DAMAGE. 2838889Sjdp */ 2933965Sjdp 3038889Sjdp#include <sys/cdefs.h> 3133965Sjdp__FBSDID("$FreeBSD: head/sys/netinet6/ip6_ipsec.c 215701 2010-11-22 19:32:54Z dim $"); 3233965Sjdp 3338889Sjdp#include "opt_inet6.h" 3433965Sjdp#include "opt_ipsec.h" 3560484Sobrien 3660484Sobrien#include <sys/param.h> 3738889Sjdp#include <sys/systm.h> 3838889Sjdp#include <sys/kernel.h> 3938889Sjdp#include <sys/mac.h> 4033965Sjdp#include <sys/malloc.h> 4138889Sjdp#include <sys/mbuf.h> 4233965Sjdp#include <sys/protosw.h> 4338889Sjdp#include <sys/socket.h> 4438889Sjdp#include <sys/socketvar.h> 4538889Sjdp#include <sys/sysctl.h> 4638889Sjdp 4738889Sjdp#include <net/if.h> 4838889Sjdp#include <net/route.h> 4960484Sobrien#include <net/vnet.h> 5033965Sjdp 5138889Sjdp#include <netinet/in.h> 5238889Sjdp#include <netinet/in_systm.h> 5333965Sjdp#include <netinet/in_var.h> 5438889Sjdp#include <netinet/ip.h> 5538889Sjdp#include <netinet/ip6.h> 5638889Sjdp#include <netinet/in_pcb.h> 5738889Sjdp#include <netinet/ip_var.h> 5838889Sjdp#include <netinet/ip_options.h> 5938889Sjdp 6038889Sjdp#include <machine/in_cksum.h> 6138889Sjdp 6238889Sjdp#ifdef IPSEC 6338889Sjdp#include <netipsec/ipsec.h> 6438889Sjdp#include <netipsec/ipsec6.h> 6538889Sjdp#include <netipsec/xform.h> 6638889Sjdp#include <netipsec/key.h> 6760484Sobrien#ifdef IPSEC_DEBUG 6838889Sjdp#include <netipsec/key_debug.h> 6960484Sobrien#else 7060484Sobrien#define KEYDEBUG(lev,arg) 7133965Sjdp#endif 7260484Sobrien#endif /*IPSEC*/ 7360484Sobrien 7438889Sjdp#include <netinet6/ip6_ipsec.h> 7560484Sobrien#include <netinet6/ip6_var.h> 7660484Sobrien 7760484Sobrienextern struct protosw inet6sw[]; 7860484Sobrien 7960484Sobrien 8060484Sobrien#ifdef INET6 8160484Sobrien#ifdef IPSEC 8260484Sobrien#ifdef IPSEC_FILTERTUNNEL 8360484Sobrienstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 1; 8438889Sjdp#else 8538889Sjdpstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 0; 8638889Sjdp#endif 8738889Sjdp#define V_ip6_ipsec6_filtertunnel VNET(ip6_ipsec6_filtertunnel) 8860484Sobrien 8960484SobrienSYSCTL_DECL(_net_inet6_ipsec6); 9060484SobrienSYSCTL_VNET_INT(_net_inet6_ipsec6, OID_AUTO, 9138889Sjdp filtertunnel, CTLFLAG_RW, &VNET_NAME(ip6_ipsec6_filtertunnel), 0, 9238889Sjdp "If set filter packets from an IPsec tunnel."); 9360484Sobrien#endif /* IPSEC */ 9460484Sobrien#endif /* INET6 */ 9538889Sjdp 9660484Sobrien/* 9760484Sobrien * Check if we have to jump over firewall processing for this packet. 9838889Sjdp * Called from ip_input(). 9938889Sjdp * 1 = jump over firewall, 0 = packet goes through firewall. 10060484Sobrien */ 10138889Sjdpint 10260484Sobrienip6_ipsec_filtertunnel(struct mbuf *m) 10360484Sobrien{ 10438889Sjdp#if defined(IPSEC) 10538889Sjdp 10638889Sjdp /* 10733965Sjdp * Bypass packet filtering for packets from a tunnel. 10860484Sobrien */ 10960484Sobrien if (!V_ip6_ipsec6_filtertunnel && 11038889Sjdp m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 11133965Sjdp return 1; 11260484Sobrien#endif 11333965Sjdp return 0; 11438889Sjdp} 11533965Sjdp 11660484Sobrien/* 11760484Sobrien * Check if this packet has an active SA and needs to be dropped instead 11833965Sjdp * of forwarded. 11960484Sobrien * Called from ip_input(). 12038889Sjdp * 1 = drop packet, 0 = forward packet. 12133965Sjdp */ 12233965Sjdpint 12333965Sjdpip6_ipsec_fwd(struct mbuf *m) 12433965Sjdp{ 12533965Sjdp#ifdef IPSEC 12633965Sjdp struct m_tag *mtag; 12733965Sjdp struct tdb_ident *tdbi; 12833965Sjdp struct secpolicy *sp; 12933965Sjdp int s, error; 13033965Sjdp mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 13133965Sjdp s = splnet(); 13233965Sjdp if (mtag != NULL) { 13360484Sobrien tdbi = (struct tdb_ident *)(mtag + 1); 13460484Sobrien sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 13560484Sobrien } else { 13660484Sobrien sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 13733965Sjdp IP_FORWARDING, &error); 13833965Sjdp } 13933965Sjdp if (sp == NULL) { /* NB: can happen if error */ 14033965Sjdp splx(s); 14133965Sjdp /*XXX error stat???*/ 14233965Sjdp DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ 14338889Sjdp return 1; 14433965Sjdp } 14560484Sobrien 14633965Sjdp /* 14760484Sobrien * Check security policy against packet attributes. 14860484Sobrien */ 14933965Sjdp error = ipsec_in_reject(sp, m); 15033965Sjdp KEY_FREESP(&sp); 15133965Sjdp splx(s); 15260484Sobrien if (error) { 15333965Sjdp V_ip6stat.ip6s_cantforward++; 15433965Sjdp return 1; 15533965Sjdp } 15633965Sjdp#endif /* IPSEC */ 15733965Sjdp return 0; 15833965Sjdp} 15960484Sobrien 16033965Sjdp/* 16133965Sjdp * Check if protocol type doesn't have a further header and do IPSEC 16233965Sjdp * decryption or reject right now. Protocols with further headers get 16333965Sjdp * their IPSEC treatment within the protocol specific processing. 16460484Sobrien * Called from ip_input(). 16533965Sjdp * 1 = drop packet, 0 = continue processing packet. 16633965Sjdp */ 16733965Sjdpint 16833965Sjdpip6_ipsec_input(struct mbuf *m, int nxt) 16938889Sjdp{ 17060484Sobrien#ifdef IPSEC 17133965Sjdp struct m_tag *mtag; 17233965Sjdp struct tdb_ident *tdbi; 17338889Sjdp struct secpolicy *sp; 17433965Sjdp int s, error; 17533965Sjdp /* 17660484Sobrien * enforce IPsec policy checking if we are seeing last header. 17733965Sjdp * note that we do not visit this with protocols with pcb layer 17833965Sjdp * code - like udp/tcp/raw ip. 17933965Sjdp */ 18033965Sjdp if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && 18133965Sjdp ipsec6_in_reject(m, NULL)) { 18233965Sjdp 18333965Sjdp /* 18433965Sjdp * Check if the packet has already had IPsec processing 18533965Sjdp * done. If so, then just pass it along. This tag gets 18633965Sjdp * set during AH, ESP, etc. input handling, before the 18733965Sjdp * packet is returned to the ip input queue for delivery. 18833965Sjdp */ 18933965Sjdp mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 19033965Sjdp s = splnet(); 19160484Sobrien if (mtag != NULL) { 19233965Sjdp tdbi = (struct tdb_ident *)(mtag + 1); 19333965Sjdp sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 19433965Sjdp } else { 19533965Sjdp sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 19633965Sjdp IP_FORWARDING, &error); 19733965Sjdp } 19833965Sjdp if (sp != NULL) { 19933965Sjdp /* 20033965Sjdp * Check security policy against packet attributes. 20133965Sjdp */ 20238889Sjdp error = ipsec_in_reject(sp, m); 20333965Sjdp KEY_FREESP(&sp); 20433965Sjdp } else { 20533965Sjdp /* XXX error stat??? */ 20633965Sjdp error = EINVAL; 20733965Sjdp DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ 20833965Sjdp return 1; 20933965Sjdp } 21033965Sjdp splx(s); 21133965Sjdp if (error) 21233965Sjdp return 1; 21333965Sjdp } 21433965Sjdp#endif /* IPSEC */ 21533965Sjdp return 0; 21633965Sjdp} 21733965Sjdp 21833965Sjdp/* 21933965Sjdp * Called from ip6_output(). 22033965Sjdp * 1 = drop packet, 0 = continue processing packet, 22133965Sjdp * -1 = packet was reinjected and stop processing packet 22233965Sjdp */ 22333965Sjdp 22433965Sjdpint 22533965Sjdpip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, 22633965Sjdp struct ifnet **ifp, struct secpolicy **sp) 22733965Sjdp{ 22833965Sjdp#ifdef IPSEC 22933965Sjdp struct tdb_ident *tdbi; 23060484Sobrien struct m_tag *mtag; 23160484Sobrien /* XXX int s; */ 23260484Sobrien if (sp == NULL) 23360484Sobrien return 1; 23460484Sobrien mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); 23533965Sjdp if (mtag != NULL) { 23660484Sobrien tdbi = (struct tdb_ident *)(mtag + 1); 23760484Sobrien *sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); 23860484Sobrien if (*sp == NULL) 23960484Sobrien *error = -EINVAL; /* force silent drop */ 24060484Sobrien m_tag_delete(*m, mtag); 24160484Sobrien } else { 24260484Sobrien *sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, 24360484Sobrien error, inp); 24460484Sobrien } 24560484Sobrien 24660484Sobrien /* 24733965Sjdp * There are four return cases: 24833965Sjdp * sp != NULL apply IPsec policy 24960484Sobrien * sp == NULL, error == 0 no IPsec handling needed 25033965Sjdp * sp == NULL, error == -EINVAL discard packet w/o error 25133965Sjdp * sp == NULL, error != 0 discard packet, report error 25238889Sjdp */ 25333965Sjdp if (*sp != NULL) { 25433965Sjdp /* Loop detection, check if ipsec processing already done */ 25533965Sjdp KASSERT((*sp)->req != NULL, ("ip_output: no ipsec request")); 25633965Sjdp for (mtag = m_tag_first(*m); mtag != NULL; 25733965Sjdp mtag = m_tag_next(*m, mtag)) { 25838889Sjdp if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) 25960484Sobrien continue; 26033965Sjdp if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && 26138889Sjdp mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) 26233965Sjdp continue; 26333965Sjdp /* 26433965Sjdp * Check if policy has an SA associated with it. 26533965Sjdp * This can happen when an SP has yet to acquire 26633965Sjdp * an SA; e.g. on first reference. If it occurs, 26733965Sjdp * then we let ipsec4_process_packet do its thing. 26833965Sjdp */ 26933965Sjdp if ((*sp)->req->sav == NULL) 27033965Sjdp break; 27133965Sjdp tdbi = (struct tdb_ident *)(mtag + 1); 27233965Sjdp if (tdbi->spi == (*sp)->req->sav->spi && 27333965Sjdp tdbi->proto == (*sp)->req->sav->sah->saidx.proto && 27433965Sjdp bcmp(&tdbi->dst, &(*sp)->req->sav->sah->saidx.dst, 27533965Sjdp sizeof (union sockaddr_union)) == 0) { 27633965Sjdp /* 27733965Sjdp * No IPsec processing is needed, free 27833965Sjdp * reference to SP. 27933965Sjdp * 28033965Sjdp * NB: null pointer to avoid free at 28133965Sjdp * done: below. 28260484Sobrien */ 28338889Sjdp KEY_FREESP(sp), *sp = NULL; 28438889Sjdp /* XXX splx(s); */ 28533965Sjdp goto done; 28633965Sjdp } 28760484Sobrien } 28833965Sjdp 28933965Sjdp /* 29060484Sobrien * Do delayed checksums now because we send before 29160484Sobrien * this is done in the normal processing path. 29233965Sjdp */ 29333965Sjdp if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 29433965Sjdp in_delayed_cksum(*m); 29533965Sjdp (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 29633965Sjdp } 29733965Sjdp 29833965Sjdp /* 29933965Sjdp * Preserve KAME behaviour: ENOENT can be returned 30033965Sjdp * when an SA acquire is in progress. Don't propagate 30133965Sjdp * this to user-level; it confuses applications. 30233965Sjdp * 30333965Sjdp * XXX this will go away when the SADB is redone. 30433965Sjdp */ 30533965Sjdp if (*error == ENOENT) 30633965Sjdp *error = 0; 30733965Sjdp goto do_ipsec; 30833965Sjdp } else { /* sp == NULL */ 30933965Sjdp if (*error != 0) { 31033965Sjdp /* 31133965Sjdp * Hack: -EINVAL is used to signal that a packet 31233965Sjdp * should be silently discarded. This is typically 31360484Sobrien * because we asked key management for an SA and 31433965Sjdp * it was delayed (e.g. kicked up to IKE). 31533965Sjdp */ 31633965Sjdp if (*error == -EINVAL) 31733965Sjdp *error = 0; 31833965Sjdp goto bad; 31938889Sjdp } else { 32033965Sjdp /* No IPsec processing for this packet. */ 32160484Sobrien } 32233965Sjdp } 32360484Sobriendone: 32460484Sobrien return 0; 32533965Sjdpdo_ipsec: 32633965Sjdp return -1; 32733965Sjdpbad: 32860484Sobrien return 1; 32933965Sjdp#endif /* IPSEC */ 33033965Sjdp return 0; 33133965Sjdp} 33233965Sjdp 33333965Sjdp#if 0 33433965Sjdp/* 33560484Sobrien * Compute the MTU for a forwarded packet that gets IPSEC encapsulated. 33633965Sjdp * Called from ip_forward(). 33733965Sjdp * Returns MTU suggestion for ICMP needfrag reply. 33833965Sjdp */ 33933965Sjdpint 34060484Sobrienip6_ipsec_mtu(struct mbuf *m) 34133965Sjdp{ 34233965Sjdp int mtu = 0; 34333965Sjdp /* 34433965Sjdp * If the packet is routed over IPsec tunnel, tell the 34538889Sjdp * originator the tunnel MTU. 34660484Sobrien * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 34733965Sjdp * XXX quickhack!!! 34833965Sjdp */ 34938889Sjdp#ifdef IPSEC 35033965Sjdp struct secpolicy *sp = NULL; 35133965Sjdp int ipsecerror; 35260484Sobrien int ipsechdr; 35333965Sjdp struct route *ro; 35433965Sjdp sp = ipsec_getpolicybyaddr(m, 35533965Sjdp IPSEC_DIR_OUTBOUND, 35638889Sjdp IP_FORWARDING, 35733965Sjdp &ipsecerror); 35860484Sobrien if (sp != NULL) { 35933965Sjdp /* count IPsec header size */ 36060484Sobrien ipsechdr = ipsec_hdrsiz(m, IPSEC_DIR_OUTBOUND, NULL); 36160484Sobrien 36233965Sjdp /* 36333965Sjdp * find the correct route for outer IPv4 36433965Sjdp * header, compute tunnel MTU. 36560484Sobrien */ 36633965Sjdp if (sp->req != NULL && 36733965Sjdp sp->req->sav != NULL && 36833965Sjdp sp->req->sav->sah != NULL) { 36933965Sjdp ro = &sp->req->sav->sah->route_cache.sa_route; 37033965Sjdp if (ro->ro_rt && ro->ro_rt->rt_ifp) { 37133965Sjdp mtu = 37260484Sobrien ro->ro_rt->rt_rmx.rmx_mtu ? 37333965Sjdp ro->ro_rt->rt_rmx.rmx_mtu : 37433965Sjdp ro->ro_rt->rt_ifp->if_mtu; 37533965Sjdp mtu -= ipsechdr; 37633965Sjdp } 37760484Sobrien } 37833965Sjdp KEY_FREESP(&sp); 37933965Sjdp } 38033965Sjdp#endif /* IPSEC */ 38133965Sjdp /* XXX else case missing. */ 38238889Sjdp return mtu; 38360484Sobrien} 38433965Sjdp#endif 38533965Sjdp