188768458SSam Leffler /* $FreeBSD$ */ 288768458SSam Leffler /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ 388768458SSam Leffler 4c398230bSWarner Losh /*- 588768458SSam Leffler * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 688768458SSam Leffler * All rights reserved. 788768458SSam Leffler * 888768458SSam Leffler * Redistribution and use in source and binary forms, with or without 988768458SSam Leffler * modification, are permitted provided that the following conditions 1088768458SSam Leffler * are met: 1188768458SSam Leffler * 1. Redistributions of source code must retain the above copyright 1288768458SSam Leffler * notice, this list of conditions and the following disclaimer. 1388768458SSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 1488768458SSam Leffler * notice, this list of conditions and the following disclaimer in the 1588768458SSam Leffler * documentation and/or other materials provided with the distribution. 1688768458SSam Leffler * 3. Neither the name of the project nor the names of its contributors 1788768458SSam Leffler * may be used to endorse or promote products derived from this software 1888768458SSam Leffler * without specific prior written permission. 1988768458SSam Leffler * 2088768458SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2188768458SSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2288768458SSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2388768458SSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2488768458SSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2588768458SSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2688768458SSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2788768458SSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2888768458SSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2988768458SSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3088768458SSam Leffler * SUCH DAMAGE. 3188768458SSam Leffler */ 3288768458SSam Leffler 3388768458SSam Leffler /* 3488768458SSam Leffler * IPsec controller part. 3588768458SSam Leffler */ 3688768458SSam Leffler 3788768458SSam Leffler #include "opt_inet.h" 3888768458SSam Leffler #include "opt_inet6.h" 3988768458SSam Leffler #include "opt_ipsec.h" 4088768458SSam Leffler 4188768458SSam Leffler #include <sys/param.h> 4288768458SSam Leffler #include <sys/systm.h> 4388768458SSam Leffler #include <sys/malloc.h> 4488768458SSam Leffler #include <sys/mbuf.h> 4588768458SSam Leffler #include <sys/domain.h> 4646ee43b2SRobert Watson #include <sys/priv.h> 4788768458SSam Leffler #include <sys/protosw.h> 4888768458SSam Leffler #include <sys/socket.h> 4988768458SSam Leffler #include <sys/socketvar.h> 5088768458SSam Leffler #include <sys/errno.h> 51ef91a976SAndrey V. Elsukov #include <sys/hhook.h> 5288768458SSam Leffler #include <sys/time.h> 5388768458SSam Leffler #include <sys/kernel.h> 5488768458SSam Leffler #include <sys/syslog.h> 5588768458SSam Leffler #include <sys/sysctl.h> 5688768458SSam Leffler #include <sys/proc.h> 5788768458SSam Leffler 5888768458SSam Leffler #include <net/if.h> 59ef91a976SAndrey V. Elsukov #include <net/if_enc.h> 6076039bc8SGleb Smirnoff #include <net/if_var.h> 61eddfbb76SRobert Watson #include <net/vnet.h> 6288768458SSam Leffler 6388768458SSam Leffler #include <netinet/in.h> 6488768458SSam Leffler #include <netinet/in_systm.h> 6588768458SSam Leffler #include <netinet/ip.h> 6688768458SSam Leffler #include <netinet/ip_var.h> 6788768458SSam Leffler #include <netinet/in_var.h> 6888768458SSam Leffler #include <netinet/udp.h> 6988768458SSam Leffler #include <netinet/udp_var.h> 7088768458SSam Leffler #include <netinet/tcp.h> 7188768458SSam Leffler #include <netinet/udp.h> 7288768458SSam Leffler 7388768458SSam Leffler #include <netinet/ip6.h> 7488768458SSam Leffler #ifdef INET6 7588768458SSam Leffler #include <netinet6/ip6_var.h> 7688768458SSam Leffler #endif 7788768458SSam Leffler #include <netinet/in_pcb.h> 7888768458SSam Leffler #ifdef INET6 7988768458SSam Leffler #include <netinet/icmp6.h> 8088768458SSam Leffler #endif 8188768458SSam Leffler 822cb64cb2SGeorge V. Neville-Neil #include <sys/types.h> 8388768458SSam Leffler #include <netipsec/ipsec.h> 8488768458SSam Leffler #ifdef INET6 8588768458SSam Leffler #include <netipsec/ipsec6.h> 8688768458SSam Leffler #endif 8788768458SSam Leffler #include <netipsec/ah_var.h> 8888768458SSam Leffler #include <netipsec/esp_var.h> 8988768458SSam Leffler #include <netipsec/ipcomp.h> /*XXX*/ 9088768458SSam Leffler #include <netipsec/ipcomp_var.h> 91fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 9288768458SSam Leffler 9388768458SSam Leffler #include <netipsec/key.h> 9488768458SSam Leffler #include <netipsec/keydb.h> 9588768458SSam Leffler #include <netipsec/key_debug.h> 9688768458SSam Leffler 9788768458SSam Leffler #include <netipsec/xform.h> 9888768458SSam Leffler 9988768458SSam Leffler #include <machine/in_cksum.h> 10088768458SSam Leffler 1017aee3dd1SSam Leffler #include <opencrypto/cryptodev.h> 1027aee3dd1SSam Leffler 103de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */ 104db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec4stat); 105db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec4stat); 106db8c0879SAndrey V. Elsukov 107db8c0879SAndrey V. Elsukov #ifdef VIMAGE 108db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec4stat); 109db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 110db8c0879SAndrey V. Elsukov 111eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_offsetmask) = 0; /* maybe IP_DF? */ 112eddfbb76SRobert Watson /* DF bit on encap. 0: clear 1: set 2: copy */ 113eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_dfbit) = 0; 114eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE; 115eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE; 116eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE; 117eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE; 118eddfbb76SRobert Watson /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 119eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_ecn) = 0; 120eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_randpad) = -1; 121eddfbb76SRobert Watson 122fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, ip4_filtertunnel) = 0; 123fcf59617SAndrey V. Elsukov #define V_ip4_filtertunnel VNET(ip4_filtertunnel) 124fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, check_policy_history) = 0; 125fcf59617SAndrey V. Elsukov #define V_check_policy_history VNET(check_policy_history) 126fcf59617SAndrey V. Elsukov static VNET_DEFINE(struct secpolicy *, def_policy) = NULL; 12793201211SAndrey V. Elsukov #define V_def_policy VNET(def_policy) 128fcf59617SAndrey V. Elsukov static int 129fcf59617SAndrey V. Elsukov sysctl_def_policy(SYSCTL_HANDLER_ARGS) 130fcf59617SAndrey V. Elsukov { 131fcf59617SAndrey V. Elsukov int error, value; 132fcf59617SAndrey V. Elsukov 133fcf59617SAndrey V. Elsukov value = V_def_policy->policy; 134fcf59617SAndrey V. Elsukov error = sysctl_handle_int(oidp, &value, 0, req); 135fcf59617SAndrey V. Elsukov if (error == 0) { 136fcf59617SAndrey V. Elsukov if (value != IPSEC_POLICY_DISCARD && 137fcf59617SAndrey V. Elsukov value != IPSEC_POLICY_NONE) 138fcf59617SAndrey V. Elsukov return (EINVAL); 139fcf59617SAndrey V. Elsukov V_def_policy->policy = value; 140fcf59617SAndrey V. Elsukov } 141fcf59617SAndrey V. Elsukov return (error); 142fcf59617SAndrey V. Elsukov } 143fcf59617SAndrey V. Elsukov 14488768458SSam Leffler /* 14588768458SSam Leffler * Crypto support requirements: 14688768458SSam Leffler * 14788768458SSam Leffler * 1 require hardware support 14888768458SSam Leffler * -1 require software support 14988768458SSam Leffler * 0 take anything 15088768458SSam Leffler */ 151eddfbb76SRobert Watson VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 152fcf59617SAndrey V. Elsukov /* 153fcf59617SAndrey V. Elsukov * TCP/UDP checksum handling policy for transport mode NAT-T (RFC3948) 154fcf59617SAndrey V. Elsukov * 155fcf59617SAndrey V. Elsukov * 0 - auto: incrementally recompute, when checksum delta is known; 156fcf59617SAndrey V. Elsukov * if checksum delta isn't known, reset checksum to zero for UDP, 157fcf59617SAndrey V. Elsukov * and mark csum_flags as valid for TCP. 158fcf59617SAndrey V. Elsukov * 1 - fully recompute TCP/UDP checksum. 159fcf59617SAndrey V. Elsukov */ 160fcf59617SAndrey V. Elsukov VNET_DEFINE(int, natt_cksum_policy) = 0; 16188768458SSam Leffler 16213a6cf24SBjoern A. Zeeb FEATURE(ipsec, "Internet Protocol Security (IPsec)"); 16313a6cf24SBjoern A. Zeeb FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')"); 16413a6cf24SBjoern A. Zeeb 16588768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec); 16688768458SSam Leffler 16788768458SSam Leffler /* net.inet.ipsec */ 168fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, 169fcf59617SAndrey V. Elsukov CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW, 0, 0, sysctl_def_policy, "I", 170be6b1304STom Rhodes "IPsec default policy."); 1716df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1726df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0, 1738b615593SMarko Zec "Default ESP transport mode level"); 1746df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1756df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0, 1768b615593SMarko Zec "Default ESP tunnel mode level."); 1776df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1786df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0, 1798b615593SMarko Zec "AH transfer mode default level."); 1806df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 1816df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0, 1828b615593SMarko Zec "AH tunnel mode default level."); 1836df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, 1846df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, 185fcf59617SAndrey V. Elsukov "If set, clear type-of-service field when doing AH computation."); 1866df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask, 1876df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_offsetmask), 0, 188fcf59617SAndrey V. Elsukov "If not set, clear offset field mask when doing AH computation."); 1896df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit, 1906df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0, 1918b615593SMarko Zec "Do not fragment bit on encap."); 1926df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, 1936df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0, 194be6b1304STom Rhodes "Explicit Congestion Notification handling."); 1956df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support, 1966df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0, 197be6b1304STom Rhodes "Crypto driver selection."); 198fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, check_policy_history, 199fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(check_policy_history), 0, 200fcf59617SAndrey V. Elsukov "Use strict check of inbound packets to security policy compliance."); 201fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, natt_cksum_policy, 202fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(natt_cksum_policy), 0, 203fcf59617SAndrey V. Elsukov "Method to fix TCP/UDP checksum for transport mode IPsec after NAT."); 204fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, filtertunnel, 205fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_filtertunnel), 0, 206fcf59617SAndrey V. Elsukov "If set, filter packets from an IPsec tunnel."); 207db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat, 208db8c0879SAndrey V. Elsukov ipsec4stat, "IPsec IPv4 statistics."); 20988768458SSam Leffler 2106131838bSPawel Jakub Dawidek #ifdef REGRESSION 211dfa9422bSPawel Jakub Dawidek /* 212dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 213dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 214dfa9422bSPawel Jakub Dawidek */ 215eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_replay) = 0; 2166df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, 2176df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0, 218eddfbb76SRobert Watson "Emulate replay attack"); 219dfa9422bSPawel Jakub Dawidek /* 220dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 221dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 222dfa9422bSPawel Jakub Dawidek */ 223eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_integrity) = 0; 2246df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, 2256df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0, 226eddfbb76SRobert Watson "Emulate man-in-the-middle attack"); 2276131838bSPawel Jakub Dawidek #endif 228dfa9422bSPawel Jakub Dawidek 22988768458SSam Leffler #ifdef INET6 230db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec6stat); 231db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec6stat); 232db8c0879SAndrey V. Elsukov 233db8c0879SAndrey V. Elsukov #ifdef VIMAGE 234db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec6stat); 235db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 236db8c0879SAndrey V. Elsukov 237eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE; 238eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE; 239eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE; 240eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE; 241eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ipsec_ecn) = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 24288768458SSam Leffler 243fcf59617SAndrey V. Elsukov static VNET_DEFINE(int, ip6_filtertunnel) = 0; 244fcf59617SAndrey V. Elsukov #define V_ip6_filtertunnel VNET(ip6_filtertunnel) 245fcf59617SAndrey V. Elsukov 24688768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6); 24788768458SSam Leffler 24888768458SSam Leffler /* net.inet6.ipsec6 */ 249fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, 250fcf59617SAndrey V. Elsukov CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW, 0, 0, sysctl_def_policy, "I", 2518b615593SMarko Zec "IPsec default policy."); 2526df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 2536df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0, 2548b615593SMarko Zec "Default ESP transport mode level."); 2556df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 2566df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0, 2578b615593SMarko Zec "Default ESP tunnel mode level."); 2586df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 2596df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0, 2608b615593SMarko Zec "AH transfer mode default level."); 2616df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 2626df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0, 2638b615593SMarko Zec "AH tunnel mode default level."); 2646df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, 2656df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0, 2663377c961STom Rhodes "Explicit Congestion Notification handling."); 267fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet6_ipsec6, OID_AUTO, filtertunnel, 268fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_filtertunnel), 0, 269fcf59617SAndrey V. Elsukov "If set, filter packets from an IPsec tunnel."); 270db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats, 271db8c0879SAndrey V. Elsukov struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics."); 27288768458SSam Leffler #endif /* INET6 */ 27388768458SSam Leffler 274fcf59617SAndrey V. Elsukov static int ipsec_in_reject(struct secpolicy *, struct inpcb *, 275fcf59617SAndrey V. Elsukov const struct mbuf *); 276fcf59617SAndrey V. Elsukov 277fcf59617SAndrey V. Elsukov #ifdef INET 278fcf59617SAndrey V. Elsukov static void ipsec4_get_ulp(const struct mbuf *, struct secpolicyindex *, int); 279fcf59617SAndrey V. Elsukov static void ipsec4_setspidx_ipaddr(const struct mbuf *, 280fcf59617SAndrey V. Elsukov struct secpolicyindex *); 281fcf59617SAndrey V. Elsukov #endif 28288768458SSam Leffler #ifdef INET6 283efb10c3cSAndrey V. Elsukov static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); 284fcf59617SAndrey V. Elsukov static void ipsec6_setspidx_ipaddr(const struct mbuf *, 285fcf59617SAndrey V. Elsukov struct secpolicyindex *); 28688768458SSam Leffler #endif 2876464079fSSam Leffler 28888768458SSam Leffler /* 28988768458SSam Leffler * Return a held reference to the default SP. 29088768458SSam Leffler */ 29188768458SSam Leffler static struct secpolicy * 292fcf59617SAndrey V. Elsukov key_allocsp_default(void) 293fcf59617SAndrey V. Elsukov { 294fcf59617SAndrey V. Elsukov 295fcf59617SAndrey V. Elsukov key_addref(V_def_policy); 296fcf59617SAndrey V. Elsukov return (V_def_policy); 297fcf59617SAndrey V. Elsukov } 298fcf59617SAndrey V. Elsukov 299fcf59617SAndrey V. Elsukov static void 300fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(struct inpcb *inp, u_int dir) 30188768458SSam Leffler { 30288768458SSam Leffler struct secpolicy *sp; 30388768458SSam Leffler 304fcf59617SAndrey V. Elsukov INP_WLOCK_ASSERT(inp); 305fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 306fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_INBOUND_POLICY) 307fcf59617SAndrey V. Elsukov return; 308fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_in; 309fcf59617SAndrey V. Elsukov inp->inp_sp->sp_in = NULL; 310fcf59617SAndrey V. Elsukov } else { 311fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_OUTBOUND_POLICY) 312fcf59617SAndrey V. Elsukov return; 313fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_out; 314fcf59617SAndrey V. Elsukov inp->inp_sp->sp_out = NULL; 31588768458SSam Leffler } 316fcf59617SAndrey V. Elsukov if (sp != NULL) 317fcf59617SAndrey V. Elsukov key_freesp(&sp); /* release extra reference */ 31888768458SSam Leffler } 31988768458SSam Leffler 320fcf59617SAndrey V. Elsukov static void 321fcf59617SAndrey V. Elsukov ipsec_cachepolicy(struct inpcb *inp, struct secpolicy *sp, u_int dir) 322fcf59617SAndrey V. Elsukov { 323fcf59617SAndrey V. Elsukov uint32_t genid; 324fcf59617SAndrey V. Elsukov int downgrade; 325fcf59617SAndrey V. Elsukov 326fcf59617SAndrey V. Elsukov INP_LOCK_ASSERT(inp); 327fcf59617SAndrey V. Elsukov 328fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 329fcf59617SAndrey V. Elsukov /* Do we have configured PCB policy? */ 330fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_OUTBOUND_POLICY) 331fcf59617SAndrey V. Elsukov return; 332fcf59617SAndrey V. Elsukov /* Another thread has already set cached policy */ 333fcf59617SAndrey V. Elsukov if (inp->inp_sp->sp_out != NULL) 334fcf59617SAndrey V. Elsukov return; 33588768458SSam Leffler /* 336fcf59617SAndrey V. Elsukov * Do not cache OUTBOUND policy if PCB isn't connected, 337fcf59617SAndrey V. Elsukov * i.e. foreign address is INADDR_ANY/UNSPECIFIED. 33888768458SSam Leffler */ 339fcf59617SAndrey V. Elsukov #ifdef INET 340fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV4) != 0 && 341fcf59617SAndrey V. Elsukov inp->inp_faddr.s_addr == INADDR_ANY) 342fcf59617SAndrey V. Elsukov return; 343fcf59617SAndrey V. Elsukov #endif 344fcf59617SAndrey V. Elsukov #ifdef INET6 345fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV6) != 0 && 346fcf59617SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 347fcf59617SAndrey V. Elsukov return; 348fcf59617SAndrey V. Elsukov #endif 349fcf59617SAndrey V. Elsukov } else { 350fcf59617SAndrey V. Elsukov /* Do we have configured PCB policy? */ 351fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_INBOUND_POLICY) 352fcf59617SAndrey V. Elsukov return; 353fcf59617SAndrey V. Elsukov /* Another thread has already set cached policy */ 354fcf59617SAndrey V. Elsukov if (inp->inp_sp->sp_in != NULL) 355fcf59617SAndrey V. Elsukov return; 35688768458SSam Leffler /* 357fcf59617SAndrey V. Elsukov * Do not cache INBOUND policy for listen socket, 358fcf59617SAndrey V. Elsukov * that is bound to INADDR_ANY/UNSPECIFIED address. 35988768458SSam Leffler */ 360fcf59617SAndrey V. Elsukov #ifdef INET 361fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV4) != 0 && 362fcf59617SAndrey V. Elsukov inp->inp_faddr.s_addr == INADDR_ANY) 363fcf59617SAndrey V. Elsukov return; 364fcf59617SAndrey V. Elsukov #endif 365fcf59617SAndrey V. Elsukov #ifdef INET6 366fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV6) != 0 && 367fcf59617SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 368fcf59617SAndrey V. Elsukov return; 369fcf59617SAndrey V. Elsukov #endif 370c1fc5e96SErmal Luçi } 371fcf59617SAndrey V. Elsukov downgrade = 0; 372fcf59617SAndrey V. Elsukov if (!INP_WLOCKED(inp)) { 373fcf59617SAndrey V. Elsukov if ((downgrade = INP_TRY_UPGRADE(inp)) == 0) 374fcf59617SAndrey V. Elsukov return; 37588768458SSam Leffler } 376fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) 377fcf59617SAndrey V. Elsukov inp->inp_sp->sp_out = sp; 37888768458SSam Leffler else 379fcf59617SAndrey V. Elsukov inp->inp_sp->sp_in = sp; 380fcf59617SAndrey V. Elsukov /* 381fcf59617SAndrey V. Elsukov * SP is already referenced by the lookup code. 382fcf59617SAndrey V. Elsukov * We take extra reference here to avoid race in the 383fcf59617SAndrey V. Elsukov * ipsec_getpcbpolicy() function - SP will not be freed in the 384fcf59617SAndrey V. Elsukov * time between we take SP pointer from the cache and key_addref() 385fcf59617SAndrey V. Elsukov * call. 386fcf59617SAndrey V. Elsukov */ 387fcf59617SAndrey V. Elsukov key_addref(sp); 388fcf59617SAndrey V. Elsukov genid = key_getspgen(); 389fcf59617SAndrey V. Elsukov if (genid != inp->inp_sp->genid) { 390fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, dir); 391fcf59617SAndrey V. Elsukov inp->inp_sp->genid = genid; 39288768458SSam Leffler } 393fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 394fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): cached %s SP(%p)\n", 395fcf59617SAndrey V. Elsukov __func__, inp, dir == IPSEC_DIR_OUTBOUND ? "OUTBOUND": 396fcf59617SAndrey V. Elsukov "INBOUND", sp)); 397fcf59617SAndrey V. Elsukov if (downgrade != 0) 398fcf59617SAndrey V. Elsukov INP_DOWNGRADE(inp); 399fcf59617SAndrey V. Elsukov } 400fcf59617SAndrey V. Elsukov 401fcf59617SAndrey V. Elsukov static struct secpolicy * 402fcf59617SAndrey V. Elsukov ipsec_checkpolicy(struct secpolicy *sp, struct inpcb *inp, int *error) 403fcf59617SAndrey V. Elsukov { 404fcf59617SAndrey V. Elsukov 405fcf59617SAndrey V. Elsukov /* Save found OUTBOUND policy into PCB SP cache. */ 406fcf59617SAndrey V. Elsukov if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_out == NULL) 407fcf59617SAndrey V. Elsukov ipsec_cachepolicy(inp, sp, IPSEC_DIR_OUTBOUND); 408fcf59617SAndrey V. Elsukov 40988768458SSam Leffler switch (sp->policy) { 41088768458SSam Leffler default: 4119ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 412de47c390SBjoern A. Zeeb /* FALLTHROUGH */ 41388768458SSam Leffler case IPSEC_POLICY_DISCARD: 414de47c390SBjoern A. Zeeb *error = -EINVAL; /* Packet is discarded by caller. */ 415fcf59617SAndrey V. Elsukov /* FALLTHROUGH */ 41688768458SSam Leffler case IPSEC_POLICY_BYPASS: 41788768458SSam Leffler case IPSEC_POLICY_NONE: 418fcf59617SAndrey V. Elsukov key_freesp(&sp); 419de47c390SBjoern A. Zeeb sp = NULL; /* NB: force NULL result. */ 42088768458SSam Leffler break; 42188768458SSam Leffler case IPSEC_POLICY_IPSEC: 422fcf59617SAndrey V. Elsukov /* XXXAE: handle LARVAL SP */ 42388768458SSam Leffler break; 42488768458SSam Leffler } 425fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 426fcf59617SAndrey V. Elsukov printf("%s: get SP(%p), error %d\n", __func__, sp, *error)); 427de47c390SBjoern A. Zeeb return (sp); 42888768458SSam Leffler } 42988768458SSam Leffler 430fcf59617SAndrey V. Elsukov static struct secpolicy * 431fcf59617SAndrey V. Elsukov ipsec_getpcbpolicy(struct inpcb *inp, u_int dir) 43288768458SSam Leffler { 433fcf59617SAndrey V. Elsukov struct secpolicy *sp; 434fcf59617SAndrey V. Elsukov int flags, downgrade; 43588768458SSam Leffler 436fcf59617SAndrey V. Elsukov if (inp == NULL || inp->inp_sp == NULL) 437fcf59617SAndrey V. Elsukov return (NULL); 43888768458SSam Leffler 439fcf59617SAndrey V. Elsukov INP_LOCK_ASSERT(inp); 440fcf59617SAndrey V. Elsukov 441fcf59617SAndrey V. Elsukov flags = inp->inp_sp->flags; 442fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 443fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_out; 444fcf59617SAndrey V. Elsukov flags &= INP_OUTBOUND_POLICY; 44588768458SSam Leffler } else { 446fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_in; 447fcf59617SAndrey V. Elsukov flags &= INP_INBOUND_POLICY; 44888768458SSam Leffler } 44988768458SSam Leffler /* 450fcf59617SAndrey V. Elsukov * Check flags. If we have PCB SP, just return it. 451fcf59617SAndrey V. Elsukov * Otherwise we need to check that cached SP entry isn't stale. 45288768458SSam Leffler */ 453fcf59617SAndrey V. Elsukov if (flags == 0) { 454fcf59617SAndrey V. Elsukov if (sp == NULL) 455fcf59617SAndrey V. Elsukov return (NULL); 456fcf59617SAndrey V. Elsukov if (inp->inp_sp->genid != key_getspgen()) { 457fcf59617SAndrey V. Elsukov /* Invalidate the cache. */ 458fcf59617SAndrey V. Elsukov downgrade = 0; 459fcf59617SAndrey V. Elsukov if (!INP_WLOCKED(inp)) { 460fcf59617SAndrey V. Elsukov if ((downgrade = INP_TRY_UPGRADE(inp)) == 0) 461fcf59617SAndrey V. Elsukov return (NULL); 462fcf59617SAndrey V. Elsukov } 463fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, IPSEC_DIR_OUTBOUND); 464fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, IPSEC_DIR_INBOUND); 465fcf59617SAndrey V. Elsukov if (downgrade != 0) 466fcf59617SAndrey V. Elsukov INP_DOWNGRADE(inp); 467fcf59617SAndrey V. Elsukov return (NULL); 468fcf59617SAndrey V. Elsukov } 469fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 470fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): cache hit SP(%p)\n", 471fcf59617SAndrey V. Elsukov __func__, inp, sp)); 472fcf59617SAndrey V. Elsukov /* Return referenced cached policy */ 473fcf59617SAndrey V. Elsukov } 474fcf59617SAndrey V. Elsukov key_addref(sp); 475fcf59617SAndrey V. Elsukov return (sp); 47688768458SSam Leffler } 47788768458SSam Leffler 478fcf59617SAndrey V. Elsukov #ifdef INET 47988768458SSam Leffler static void 480efb10c3cSAndrey V. Elsukov ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx, 481efb10c3cSAndrey V. Elsukov int needport) 48288768458SSam Leffler { 483fcf59617SAndrey V. Elsukov uint8_t nxt; 48488768458SSam Leffler int off; 48588768458SSam Leffler 486de47c390SBjoern A. Zeeb /* Sanity check. */ 487fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip), 488fcf59617SAndrey V. Elsukov ("packet too short")); 48988768458SSam Leffler 49087a25418SErmal Luçi if (m->m_len >= sizeof (struct ip)) { 491efb10c3cSAndrey V. Elsukov const struct ip *ip = mtod(m, const struct ip *); 4928f134647SGleb Smirnoff if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) 49388768458SSam Leffler goto done; 49488768458SSam Leffler off = ip->ip_hl << 2; 49588768458SSam Leffler nxt = ip->ip_p; 49688768458SSam Leffler } else { 49788768458SSam Leffler struct ip ih; 49888768458SSam Leffler 49988768458SSam Leffler m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 5008f134647SGleb Smirnoff if (ih.ip_off & htons(IP_MF | IP_OFFMASK)) 50188768458SSam Leffler goto done; 50288768458SSam Leffler off = ih.ip_hl << 2; 50388768458SSam Leffler nxt = ih.ip_p; 50488768458SSam Leffler } 50588768458SSam Leffler 50688768458SSam Leffler while (off < m->m_pkthdr.len) { 50788768458SSam Leffler struct ip6_ext ip6e; 50888768458SSam Leffler struct tcphdr th; 50988768458SSam Leffler struct udphdr uh; 51088768458SSam Leffler 51188768458SSam Leffler switch (nxt) { 51288768458SSam Leffler case IPPROTO_TCP: 51388768458SSam Leffler spidx->ul_proto = nxt; 51488768458SSam Leffler if (!needport) 51588768458SSam Leffler goto done_proto; 51688768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 51788768458SSam Leffler goto done; 51888768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 51988768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 52088768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 52188768458SSam Leffler return; 52288768458SSam Leffler case IPPROTO_UDP: 52388768458SSam Leffler spidx->ul_proto = nxt; 52488768458SSam Leffler if (!needport) 52588768458SSam Leffler goto done_proto; 52688768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 52788768458SSam Leffler goto done; 52888768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 52988768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 53088768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 53188768458SSam Leffler return; 53288768458SSam Leffler case IPPROTO_AH: 533afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 53488768458SSam Leffler goto done; 535de47c390SBjoern A. Zeeb /* XXX Sigh, this works but is totally bogus. */ 53688768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 53788768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 53888768458SSam Leffler nxt = ip6e.ip6e_nxt; 53988768458SSam Leffler break; 54088768458SSam Leffler case IPPROTO_ICMP: 54188768458SSam Leffler default: 542de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 54388768458SSam Leffler spidx->ul_proto = nxt; 54488768458SSam Leffler goto done_proto; 54588768458SSam Leffler } 54688768458SSam Leffler } 54788768458SSam Leffler done: 54888768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 54988768458SSam Leffler done_proto: 55088768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 55188768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 552fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 553fcf59617SAndrey V. Elsukov printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL)); 55488768458SSam Leffler } 55588768458SSam Leffler 556fcf59617SAndrey V. Elsukov static void 557efb10c3cSAndrey V. Elsukov ipsec4_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) 55888768458SSam Leffler { 55988768458SSam Leffler 560fcf59617SAndrey V. Elsukov ipsec4_setsockaddrs(m, &spidx->src, &spidx->dst); 56188768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 56288768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 56388768458SSam Leffler } 56488768458SSam Leffler 565fcf59617SAndrey V. Elsukov static struct secpolicy * 566*22bbefb2SAndrey V. Elsukov ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir, 567*22bbefb2SAndrey V. Elsukov int needport) 568fcf59617SAndrey V. Elsukov { 569fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 570fcf59617SAndrey V. Elsukov struct secpolicy *sp; 571fcf59617SAndrey V. Elsukov 572fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, dir); 573fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(dir)) { 574fcf59617SAndrey V. Elsukov /* Make an index to look for a policy. */ 575fcf59617SAndrey V. Elsukov ipsec4_setspidx_ipaddr(m, &spidx); 576fcf59617SAndrey V. Elsukov /* Fill ports in spidx if we have inpcb. */ 577*22bbefb2SAndrey V. Elsukov ipsec4_get_ulp(m, &spidx, needport); 578fcf59617SAndrey V. Elsukov spidx.dir = dir; 579fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, dir); 580fcf59617SAndrey V. Elsukov } 581fcf59617SAndrey V. Elsukov if (sp == NULL) /* No SP found, use system default. */ 582fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 583fcf59617SAndrey V. Elsukov return (sp); 584fcf59617SAndrey V. Elsukov } 585fcf59617SAndrey V. Elsukov 586fcf59617SAndrey V. Elsukov /* 587fcf59617SAndrey V. Elsukov * Check security policy for *OUTBOUND* IPv4 packet. 588fcf59617SAndrey V. Elsukov */ 589fcf59617SAndrey V. Elsukov struct secpolicy * 590*22bbefb2SAndrey V. Elsukov ipsec4_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error, 591*22bbefb2SAndrey V. Elsukov int needport) 592fcf59617SAndrey V. Elsukov { 593fcf59617SAndrey V. Elsukov struct secpolicy *sp; 594fcf59617SAndrey V. Elsukov 595fcf59617SAndrey V. Elsukov *error = 0; 596*22bbefb2SAndrey V. Elsukov sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport); 597fcf59617SAndrey V. Elsukov if (sp != NULL) 598fcf59617SAndrey V. Elsukov sp = ipsec_checkpolicy(sp, inp, error); 599fcf59617SAndrey V. Elsukov if (sp == NULL) { 600fcf59617SAndrey V. Elsukov switch (*error) { 601fcf59617SAndrey V. Elsukov case 0: /* No IPsec required: BYPASS or NONE */ 602fcf59617SAndrey V. Elsukov break; 603fcf59617SAndrey V. Elsukov case -EINVAL: 604fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_out_polvio); 605fcf59617SAndrey V. Elsukov break; 606fcf59617SAndrey V. Elsukov default: 607fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_out_inval); 608fcf59617SAndrey V. Elsukov } 609fcf59617SAndrey V. Elsukov } 610fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 611fcf59617SAndrey V. Elsukov printf("%s: using SP(%p), error %d\n", __func__, sp, *error)); 612fcf59617SAndrey V. Elsukov if (sp != NULL) 613fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 614fcf59617SAndrey V. Elsukov return (sp); 615fcf59617SAndrey V. Elsukov } 616fcf59617SAndrey V. Elsukov 617fcf59617SAndrey V. Elsukov /* 618fcf59617SAndrey V. Elsukov * Check IPv4 packet against *INBOUND* security policy. 619fcf59617SAndrey V. Elsukov * This function is called from tcp_input(), udp_input(), 620fcf59617SAndrey V. Elsukov * rip_input() and sctp_input(). 621fcf59617SAndrey V. Elsukov */ 622fcf59617SAndrey V. Elsukov int 623fcf59617SAndrey V. Elsukov ipsec4_in_reject(const struct mbuf *m, struct inpcb *inp) 624fcf59617SAndrey V. Elsukov { 625fcf59617SAndrey V. Elsukov struct secpolicy *sp; 626fcf59617SAndrey V. Elsukov int result; 627fcf59617SAndrey V. Elsukov 628*22bbefb2SAndrey V. Elsukov sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0); 629fcf59617SAndrey V. Elsukov result = ipsec_in_reject(sp, inp, m); 630fcf59617SAndrey V. Elsukov key_freesp(&sp); 631fcf59617SAndrey V. Elsukov if (result != 0) 632fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_in_polvio); 633fcf59617SAndrey V. Elsukov return (result); 634fcf59617SAndrey V. Elsukov } 635fcf59617SAndrey V. Elsukov 636fcf59617SAndrey V. Elsukov /* 637fcf59617SAndrey V. Elsukov * IPSEC_CAP() method implementation for IPv4. 638fcf59617SAndrey V. Elsukov */ 639fcf59617SAndrey V. Elsukov int 640fcf59617SAndrey V. Elsukov ipsec4_capability(struct mbuf *m, u_int cap) 641fcf59617SAndrey V. Elsukov { 642fcf59617SAndrey V. Elsukov 643fcf59617SAndrey V. Elsukov switch (cap) { 644fcf59617SAndrey V. Elsukov case IPSEC_CAP_BYPASS_FILTER: 645fcf59617SAndrey V. Elsukov /* 646fcf59617SAndrey V. Elsukov * Bypass packet filtering for packets previously handled 647fcf59617SAndrey V. Elsukov * by IPsec. 648fcf59617SAndrey V. Elsukov */ 649fcf59617SAndrey V. Elsukov if (!V_ip4_filtertunnel && 650fcf59617SAndrey V. Elsukov m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 651fcf59617SAndrey V. Elsukov return (1); 652fcf59617SAndrey V. Elsukov return (0); 653fcf59617SAndrey V. Elsukov case IPSEC_CAP_OPERABLE: 654fcf59617SAndrey V. Elsukov /* Do we have active security policies? */ 655fcf59617SAndrey V. Elsukov if (key_havesp(IPSEC_DIR_INBOUND) != 0 || 656fcf59617SAndrey V. Elsukov key_havesp(IPSEC_DIR_OUTBOUND) != 0) 657fcf59617SAndrey V. Elsukov return (1); 658fcf59617SAndrey V. Elsukov return (0); 659fcf59617SAndrey V. Elsukov }; 660fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 661fcf59617SAndrey V. Elsukov } 662fcf59617SAndrey V. Elsukov 663fcf59617SAndrey V. Elsukov #endif /* INET */ 664fcf59617SAndrey V. Elsukov 66588768458SSam Leffler #ifdef INET6 66688768458SSam Leffler static void 667efb10c3cSAndrey V. Elsukov ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx, 668efb10c3cSAndrey V. Elsukov int needport) 66988768458SSam Leffler { 67088768458SSam Leffler struct tcphdr th; 67188768458SSam Leffler struct udphdr uh; 6720e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 673fcf59617SAndrey V. Elsukov int off, nxt; 67488768458SSam Leffler 675fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip6_hdr), 676fcf59617SAndrey V. Elsukov ("packet too short")); 67788768458SSam Leffler 678de47c390SBjoern A. Zeeb /* Set default. */ 67988768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 680fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = IPSEC_PORT_ANY; 681fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = IPSEC_PORT_ANY; 68288768458SSam Leffler 68388768458SSam Leffler nxt = -1; 68488768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 68588768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 68688768458SSam Leffler return; 68788768458SSam Leffler 68888768458SSam Leffler switch (nxt) { 68988768458SSam Leffler case IPPROTO_TCP: 69088768458SSam Leffler spidx->ul_proto = nxt; 69188768458SSam Leffler if (!needport) 69288768458SSam Leffler break; 69388768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 69488768458SSam Leffler break; 69588768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 696fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = th.th_sport; 697fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = th.th_dport; 69888768458SSam Leffler break; 69988768458SSam Leffler case IPPROTO_UDP: 70088768458SSam Leffler spidx->ul_proto = nxt; 70188768458SSam Leffler if (!needport) 70288768458SSam Leffler break; 70388768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 70488768458SSam Leffler break; 70588768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 706fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = uh.uh_sport; 707fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = uh.uh_dport; 70888768458SSam Leffler break; 70988768458SSam Leffler case IPPROTO_ICMPV6: 7100e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 7110e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 7120e3c2be4SBjoern A. Zeeb break; 7130e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 714fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = htons((uint16_t)ih.icmp6_type); 715fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = htons((uint16_t)ih.icmp6_code); 7160e3c2be4SBjoern A. Zeeb break; 71788768458SSam Leffler default: 718de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 71988768458SSam Leffler spidx->ul_proto = nxt; 72088768458SSam Leffler break; 72188768458SSam Leffler } 722fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 723fcf59617SAndrey V. Elsukov printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL)); 72488768458SSam Leffler } 72588768458SSam Leffler 726fcf59617SAndrey V. Elsukov static void 727efb10c3cSAndrey V. Elsukov ipsec6_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) 72888768458SSam Leffler { 72988768458SSam Leffler 730fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(m, &spidx->src, &spidx->dst); 73188768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 73288768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 73388768458SSam Leffler } 734fcf59617SAndrey V. Elsukov 735fcf59617SAndrey V. Elsukov static struct secpolicy * 736*22bbefb2SAndrey V. Elsukov ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir, 737*22bbefb2SAndrey V. Elsukov int needport) 738fcf59617SAndrey V. Elsukov { 739fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 740fcf59617SAndrey V. Elsukov struct secpolicy *sp; 741fcf59617SAndrey V. Elsukov 742fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, dir); 743fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(dir)) { 744fcf59617SAndrey V. Elsukov /* Make an index to look for a policy. */ 745fcf59617SAndrey V. Elsukov ipsec6_setspidx_ipaddr(m, &spidx); 746fcf59617SAndrey V. Elsukov /* Fill ports in spidx if we have inpcb. */ 747*22bbefb2SAndrey V. Elsukov ipsec6_get_ulp(m, &spidx, needport); 748fcf59617SAndrey V. Elsukov spidx.dir = dir; 749fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, dir); 750fcf59617SAndrey V. Elsukov } 751fcf59617SAndrey V. Elsukov if (sp == NULL) /* No SP found, use system default. */ 752fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 753fcf59617SAndrey V. Elsukov return (sp); 754fcf59617SAndrey V. Elsukov } 755fcf59617SAndrey V. Elsukov 756fcf59617SAndrey V. Elsukov /* 757fcf59617SAndrey V. Elsukov * Check security policy for *OUTBOUND* IPv6 packet. 758fcf59617SAndrey V. Elsukov */ 759fcf59617SAndrey V. Elsukov struct secpolicy * 760*22bbefb2SAndrey V. Elsukov ipsec6_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error, 761*22bbefb2SAndrey V. Elsukov int needport) 762fcf59617SAndrey V. Elsukov { 763fcf59617SAndrey V. Elsukov struct secpolicy *sp; 764fcf59617SAndrey V. Elsukov 765fcf59617SAndrey V. Elsukov *error = 0; 766*22bbefb2SAndrey V. Elsukov sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport); 767fcf59617SAndrey V. Elsukov if (sp != NULL) 768fcf59617SAndrey V. Elsukov sp = ipsec_checkpolicy(sp, inp, error); 769fcf59617SAndrey V. Elsukov if (sp == NULL) { 770fcf59617SAndrey V. Elsukov switch (*error) { 771fcf59617SAndrey V. Elsukov case 0: /* No IPsec required: BYPASS or NONE */ 772fcf59617SAndrey V. Elsukov break; 773fcf59617SAndrey V. Elsukov case -EINVAL: 774fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_polvio); 775fcf59617SAndrey V. Elsukov break; 776fcf59617SAndrey V. Elsukov default: 777fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_inval); 778fcf59617SAndrey V. Elsukov } 779fcf59617SAndrey V. Elsukov } 780fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 781fcf59617SAndrey V. Elsukov printf("%s: using SP(%p), error %d\n", __func__, sp, *error)); 782fcf59617SAndrey V. Elsukov if (sp != NULL) 783fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 784fcf59617SAndrey V. Elsukov return (sp); 785fcf59617SAndrey V. Elsukov } 786fcf59617SAndrey V. Elsukov 787fcf59617SAndrey V. Elsukov /* 788fcf59617SAndrey V. Elsukov * Check IPv6 packet against inbound security policy. 789fcf59617SAndrey V. Elsukov * This function is called from tcp6_input(), udp6_input(), 790fcf59617SAndrey V. Elsukov * rip6_input() and sctp_input(). 791fcf59617SAndrey V. Elsukov */ 792fcf59617SAndrey V. Elsukov int 793fcf59617SAndrey V. Elsukov ipsec6_in_reject(const struct mbuf *m, struct inpcb *inp) 794fcf59617SAndrey V. Elsukov { 795fcf59617SAndrey V. Elsukov struct secpolicy *sp; 796fcf59617SAndrey V. Elsukov int result; 797fcf59617SAndrey V. Elsukov 798*22bbefb2SAndrey V. Elsukov sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0); 799fcf59617SAndrey V. Elsukov result = ipsec_in_reject(sp, inp, m); 800fcf59617SAndrey V. Elsukov key_freesp(&sp); 801fcf59617SAndrey V. Elsukov if (result) 802fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_in_polvio); 803fcf59617SAndrey V. Elsukov return (result); 804fcf59617SAndrey V. Elsukov } 805fcf59617SAndrey V. Elsukov 806fcf59617SAndrey V. Elsukov /* 807fcf59617SAndrey V. Elsukov * IPSEC_CAP() method implementation for IPv6. 808fcf59617SAndrey V. Elsukov */ 809fcf59617SAndrey V. Elsukov int 810fcf59617SAndrey V. Elsukov ipsec6_capability(struct mbuf *m, u_int cap) 811fcf59617SAndrey V. Elsukov { 812fcf59617SAndrey V. Elsukov 813fcf59617SAndrey V. Elsukov switch (cap) { 814fcf59617SAndrey V. Elsukov case IPSEC_CAP_BYPASS_FILTER: 815fcf59617SAndrey V. Elsukov /* 816fcf59617SAndrey V. Elsukov * Bypass packet filtering for packets previously handled 817fcf59617SAndrey V. Elsukov * by IPsec. 818fcf59617SAndrey V. Elsukov */ 819fcf59617SAndrey V. Elsukov if (!V_ip6_filtertunnel && 820fcf59617SAndrey V. Elsukov m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 821fcf59617SAndrey V. Elsukov return (1); 822fcf59617SAndrey V. Elsukov return (0); 823fcf59617SAndrey V. Elsukov case IPSEC_CAP_OPERABLE: 824fcf59617SAndrey V. Elsukov /* Do we have active security policies? */ 825fcf59617SAndrey V. Elsukov if (key_havesp(IPSEC_DIR_INBOUND) != 0 || 826fcf59617SAndrey V. Elsukov key_havesp(IPSEC_DIR_OUTBOUND) != 0) 827fcf59617SAndrey V. Elsukov return (1); 828fcf59617SAndrey V. Elsukov return (0); 829fcf59617SAndrey V. Elsukov }; 830fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 831fcf59617SAndrey V. Elsukov } 832fcf59617SAndrey V. Elsukov #endif /* INET6 */ 83388768458SSam Leffler 834ef91a976SAndrey V. Elsukov int 835ef91a976SAndrey V. Elsukov ipsec_run_hhooks(struct ipsec_ctx_data *ctx, int type) 836ef91a976SAndrey V. Elsukov { 837ef91a976SAndrey V. Elsukov int idx; 838ef91a976SAndrey V. Elsukov 839ef91a976SAndrey V. Elsukov switch (ctx->af) { 840ef91a976SAndrey V. Elsukov #ifdef INET 841ef91a976SAndrey V. Elsukov case AF_INET: 842ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET; 843ef91a976SAndrey V. Elsukov break; 844ef91a976SAndrey V. Elsukov #endif 845ef91a976SAndrey V. Elsukov #ifdef INET6 846ef91a976SAndrey V. Elsukov case AF_INET6: 847ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET6; 848ef91a976SAndrey V. Elsukov break; 849ef91a976SAndrey V. Elsukov #endif 850ef91a976SAndrey V. Elsukov default: 851ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 852ef91a976SAndrey V. Elsukov } 853ef91a976SAndrey V. Elsukov if (type == HHOOK_TYPE_IPSEC_IN) 854ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_in[idx], ctx, NULL); 855ef91a976SAndrey V. Elsukov else 856ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_out[idx], ctx, NULL); 857ef91a976SAndrey V. Elsukov if (*ctx->mp == NULL) 858ef91a976SAndrey V. Elsukov return (EACCES); 859ef91a976SAndrey V. Elsukov return (0); 860ef91a976SAndrey V. Elsukov } 861ef91a976SAndrey V. Elsukov 86288768458SSam Leffler /* 863de47c390SBjoern A. Zeeb * Return current level. 86488768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 86588768458SSam Leffler */ 86688768458SSam Leffler u_int 867fcf59617SAndrey V. Elsukov ipsec_get_reqlevel(struct secpolicy *sp, u_int idx) 86888768458SSam Leffler { 869fcf59617SAndrey V. Elsukov struct ipsecrequest *isr; 87088768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 87188768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 872fcf59617SAndrey V. Elsukov u_int level = 0; 87388768458SSam Leffler 874fcf59617SAndrey V. Elsukov IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx)); 875de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */ 87688768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 877fcf59617SAndrey V. Elsukov (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE && \ 878fcf59617SAndrey V. Elsukov (lev) != IPSEC_LEVEL_UNIQUE) \ 879fcf59617SAndrey V. Elsukov ? (V_ipsec_debug ? \ 880fcf59617SAndrey V. Elsukov log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 881fcf59617SAndrey V. Elsukov (lev), IPSEC_LEVEL_REQUIRE) : 0), \ 882fcf59617SAndrey V. Elsukov (lev) = IPSEC_LEVEL_REQUIRE, (lev) : (lev)) 883fcf59617SAndrey V. Elsukov 884fcf59617SAndrey V. Elsukov /* 885fcf59617SAndrey V. Elsukov * IPsec VTI uses unique security policy with fake spidx filled 886fcf59617SAndrey V. Elsukov * with zeroes. Just return IPSEC_LEVEL_REQUIRE instead of doing 887fcf59617SAndrey V. Elsukov * full level lookup for such policies. 888fcf59617SAndrey V. Elsukov */ 889fcf59617SAndrey V. Elsukov if (sp->state == IPSEC_SPSTATE_IFNET) { 890fcf59617SAndrey V. Elsukov IPSEC_ASSERT(sp->req[idx]->level == IPSEC_LEVEL_UNIQUE, 891fcf59617SAndrey V. Elsukov ("Wrong IPsec request level %d", sp->req[idx]->level)); 892fcf59617SAndrey V. Elsukov return (IPSEC_LEVEL_REQUIRE); 893fcf59617SAndrey V. Elsukov } 89488768458SSam Leffler 895de47c390SBjoern A. Zeeb /* Set default level. */ 896fcf59617SAndrey V. Elsukov switch (sp->spidx.src.sa.sa_family) { 89788768458SSam Leffler #ifdef INET 89888768458SSam Leffler case AF_INET: 899603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 900603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 901603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 902603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 90388768458SSam Leffler break; 90488768458SSam Leffler #endif 90588768458SSam Leffler #ifdef INET6 90688768458SSam Leffler case AF_INET6: 907603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 908603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 909603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 910603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 91188768458SSam Leffler break; 91288768458SSam Leffler #endif /* INET6 */ 91388768458SSam Leffler default: 9149ffa9677SSam Leffler panic("%s: unknown af %u", 915fcf59617SAndrey V. Elsukov __func__, sp->spidx.src.sa.sa_family); 91688768458SSam Leffler } 91788768458SSam Leffler 91888768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 91988768458SSam Leffler 920fcf59617SAndrey V. Elsukov isr = sp->req[idx]; 921de47c390SBjoern A. Zeeb /* Set level. */ 92288768458SSam Leffler switch (isr->level) { 92388768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 92488768458SSam Leffler switch (isr->saidx.proto) { 92588768458SSam Leffler case IPPROTO_ESP: 92688768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 92788768458SSam Leffler level = esp_net_deflev; 92888768458SSam Leffler else 92988768458SSam Leffler level = esp_trans_deflev; 93088768458SSam Leffler break; 93188768458SSam Leffler case IPPROTO_AH: 93288768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 93388768458SSam Leffler level = ah_net_deflev; 93488768458SSam Leffler else 93588768458SSam Leffler level = ah_trans_deflev; 9368381996eSSam Leffler break; 93788768458SSam Leffler case IPPROTO_IPCOMP: 93888768458SSam Leffler /* 939de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document says that 940de47c390SBjoern A. Zeeb * we shouldn't compress small packets. 94188768458SSam Leffler */ 94288768458SSam Leffler level = IPSEC_LEVEL_USE; 94388768458SSam Leffler break; 94488768458SSam Leffler default: 9459ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 94688768458SSam Leffler isr->saidx.proto); 94788768458SSam Leffler } 94888768458SSam Leffler break; 94988768458SSam Leffler 95088768458SSam Leffler case IPSEC_LEVEL_USE: 95188768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 95288768458SSam Leffler level = isr->level; 95388768458SSam Leffler break; 95488768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 95588768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 95688768458SSam Leffler break; 95788768458SSam Leffler 95888768458SSam Leffler default: 9599ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 96088768458SSam Leffler } 96188768458SSam Leffler 962de47c390SBjoern A. Zeeb return (level); 96388768458SSam Leffler } 96488768458SSam Leffler 965fcf59617SAndrey V. Elsukov static int 966fcf59617SAndrey V. Elsukov ipsec_check_history(const struct mbuf *m, struct secpolicy *sp, u_int idx) 967fcf59617SAndrey V. Elsukov { 968fcf59617SAndrey V. Elsukov struct xform_history *xh; 969fcf59617SAndrey V. Elsukov struct m_tag *mtag; 970fcf59617SAndrey V. Elsukov 971fcf59617SAndrey V. Elsukov mtag = NULL; 972fcf59617SAndrey V. Elsukov while ((mtag = m_tag_find(__DECONST(struct mbuf *, m), 973fcf59617SAndrey V. Elsukov PACKET_TAG_IPSEC_IN_DONE, mtag)) != NULL) { 974fcf59617SAndrey V. Elsukov xh = (struct xform_history *)(mtag + 1); 975fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, 976fcf59617SAndrey V. Elsukov char buf[IPSEC_ADDRSTRLEN]; 977fcf59617SAndrey V. Elsukov printf("%s: mode %s proto %u dst %s\n", __func__, 978fcf59617SAndrey V. Elsukov kdebug_secasindex_mode(xh->mode), xh->proto, 979fcf59617SAndrey V. Elsukov ipsec_address(&xh->dst, buf, sizeof(buf)))); 980fcf59617SAndrey V. Elsukov if (xh->proto != sp->req[idx]->saidx.proto) 981fcf59617SAndrey V. Elsukov continue; 982fcf59617SAndrey V. Elsukov /* If SA had IPSEC_MODE_ANY, consider this as match. */ 983fcf59617SAndrey V. Elsukov if (xh->mode != sp->req[idx]->saidx.mode && 984fcf59617SAndrey V. Elsukov xh->mode != IPSEC_MODE_ANY) 985fcf59617SAndrey V. Elsukov continue; 986fcf59617SAndrey V. Elsukov /* 987fcf59617SAndrey V. Elsukov * For transport mode IPsec request doesn't contain 988fcf59617SAndrey V. Elsukov * addresses. We need to use address from spidx. 989fcf59617SAndrey V. Elsukov */ 990fcf59617SAndrey V. Elsukov if (sp->req[idx]->saidx.mode == IPSEC_MODE_TRANSPORT) { 991fcf59617SAndrey V. Elsukov if (key_sockaddrcmp_withmask(&xh->dst.sa, 992fcf59617SAndrey V. Elsukov &sp->spidx.dst.sa, sp->spidx.prefd) != 0) 993fcf59617SAndrey V. Elsukov continue; 994fcf59617SAndrey V. Elsukov } else { 995fcf59617SAndrey V. Elsukov if (key_sockaddrcmp(&xh->dst.sa, 996fcf59617SAndrey V. Elsukov &sp->req[idx]->saidx.dst.sa, 0) != 0) 997fcf59617SAndrey V. Elsukov continue; 998fcf59617SAndrey V. Elsukov } 999fcf59617SAndrey V. Elsukov return (0); /* matched */ 1000fcf59617SAndrey V. Elsukov } 1001fcf59617SAndrey V. Elsukov return (1); 1002fcf59617SAndrey V. Elsukov } 1003fcf59617SAndrey V. Elsukov 100488768458SSam Leffler /* 100588768458SSam Leffler * Check security policy requirements against the actual 100688768458SSam Leffler * packet contents. Return one if the packet should be 100788768458SSam Leffler * reject as "invalid"; otherwiser return zero to have the 100888768458SSam Leffler * packet treated as "valid". 100988768458SSam Leffler * 101088768458SSam Leffler * OUT: 101188768458SSam Leffler * 0: valid 101288768458SSam Leffler * 1: invalid 101388768458SSam Leffler */ 1014a9b9f6b6SAndrey V. Elsukov static int 1015fcf59617SAndrey V. Elsukov ipsec_in_reject(struct secpolicy *sp, struct inpcb *inp, const struct mbuf *m) 101688768458SSam Leffler { 1017fcf59617SAndrey V. Elsukov int i; 101888768458SSam Leffler 1019fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 1020fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): using SP(%p)\n", __func__, inp, sp)); 1021fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 1022fcf59617SAndrey V. Elsukov 1023fcf59617SAndrey V. Elsukov if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_in == NULL) 1024fcf59617SAndrey V. Elsukov ipsec_cachepolicy(inp, sp, IPSEC_DIR_INBOUND); 102588768458SSam Leffler 1026de47c390SBjoern A. Zeeb /* Check policy. */ 102788768458SSam Leffler switch (sp->policy) { 102888768458SSam Leffler case IPSEC_POLICY_DISCARD: 1029de47c390SBjoern A. Zeeb return (1); 103088768458SSam Leffler case IPSEC_POLICY_BYPASS: 103188768458SSam Leffler case IPSEC_POLICY_NONE: 1032de47c390SBjoern A. Zeeb return (0); 103388768458SSam Leffler } 103488768458SSam Leffler 10359ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 10369ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 103788768458SSam Leffler 1038fcf59617SAndrey V. Elsukov /* 1039fcf59617SAndrey V. Elsukov * ipsec[46]_common_input_cb after each transform adds 1040fcf59617SAndrey V. Elsukov * PACKET_TAG_IPSEC_IN_DONE mbuf tag. It contains SPI, proto, mode 1041fcf59617SAndrey V. Elsukov * and destination address from saidx. We can compare info from 1042fcf59617SAndrey V. Elsukov * these tags with requirements in SP. 1043fcf59617SAndrey V. Elsukov */ 1044fcf59617SAndrey V. Elsukov for (i = 0; i < sp->tcount; i++) { 1045fcf59617SAndrey V. Elsukov /* 1046fcf59617SAndrey V. Elsukov * Do not check IPcomp, since IPcomp document 1047fcf59617SAndrey V. Elsukov * says that we shouldn't compress small packets. 1048fcf59617SAndrey V. Elsukov * IPComp policy should always be treated as being 1049fcf59617SAndrey V. Elsukov * in "use" level. 1050fcf59617SAndrey V. Elsukov */ 1051fcf59617SAndrey V. Elsukov if (sp->req[i]->saidx.proto == IPPROTO_IPCOMP || 1052fcf59617SAndrey V. Elsukov ipsec_get_reqlevel(sp, i) != IPSEC_LEVEL_REQUIRE) 105388768458SSam Leffler continue; 1054fcf59617SAndrey V. Elsukov if (V_check_policy_history != 0 && 1055fcf59617SAndrey V. Elsukov ipsec_check_history(m, sp, i) != 0) 1056fcf59617SAndrey V. Elsukov return (1); 1057fcf59617SAndrey V. Elsukov else switch (sp->req[i]->saidx.proto) { 105888768458SSam Leffler case IPPROTO_ESP: 105988768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 1060fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 10619ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 106288768458SSam Leffler m->m_flags)); 1063de47c390SBjoern A. Zeeb return (1); 106488768458SSam Leffler } 106588768458SSam Leffler break; 106688768458SSam Leffler case IPPROTO_AH: 106788768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 1068fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 10699ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 107088768458SSam Leffler m->m_flags)); 1071de47c390SBjoern A. Zeeb return (1); 107288768458SSam Leffler } 107388768458SSam Leffler break; 107488768458SSam Leffler } 107588768458SSam Leffler } 1076de47c390SBjoern A. Zeeb return (0); /* Valid. */ 107788768458SSam Leffler } 107888768458SSam Leffler 1079a91150daSAndrey V. Elsukov /* 1080de47c390SBjoern A. Zeeb * Compute the byte size to be occupied by IPsec header. 1081de47c390SBjoern A. Zeeb * In case it is tunnelled, it includes the size of outer IP header. 108288768458SSam Leffler */ 108388768458SSam Leffler static size_t 108497aa4a51SBjoern A. Zeeb ipsec_hdrsiz_internal(struct secpolicy *sp) 108588768458SSam Leffler { 10861f8bd75eSBjoern A. Zeeb size_t size; 1087fcf59617SAndrey V. Elsukov int i; 108888768458SSam Leffler 1089fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, printf("%s: using SP(%p)\n", __func__, sp)); 1090fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 109188768458SSam Leffler 109288768458SSam Leffler switch (sp->policy) { 109388768458SSam Leffler case IPSEC_POLICY_DISCARD: 109488768458SSam Leffler case IPSEC_POLICY_BYPASS: 109588768458SSam Leffler case IPSEC_POLICY_NONE: 1096de47c390SBjoern A. Zeeb return (0); 109788768458SSam Leffler } 109888768458SSam Leffler 10999ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 11009ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 110188768458SSam Leffler 1102fcf59617SAndrey V. Elsukov /* 1103fcf59617SAndrey V. Elsukov * XXX: for each transform we need to lookup suitable SA 1104fcf59617SAndrey V. Elsukov * and use info from SA to calculate headers size. 1105fcf59617SAndrey V. Elsukov * XXX: for NAT-T we need to cosider UDP header size. 1106fcf59617SAndrey V. Elsukov */ 11071f8bd75eSBjoern A. Zeeb size = 0; 1108fcf59617SAndrey V. Elsukov for (i = 0; i < sp->tcount; i++) { 1109fcf59617SAndrey V. Elsukov switch (sp->req[i]->saidx.proto) { 111088768458SSam Leffler case IPPROTO_ESP: 1111fcf59617SAndrey V. Elsukov size += esp_hdrsiz(NULL); 111288768458SSam Leffler break; 111388768458SSam Leffler case IPPROTO_AH: 1114fcf59617SAndrey V. Elsukov size += ah_hdrsiz(NULL); 111588768458SSam Leffler break; 111688768458SSam Leffler case IPPROTO_IPCOMP: 1117fcf59617SAndrey V. Elsukov size += sizeof(struct ipcomp); 111888768458SSam Leffler break; 111988768458SSam Leffler } 112088768458SSam Leffler 1121fcf59617SAndrey V. Elsukov if (sp->req[i]->saidx.mode == IPSEC_MODE_TUNNEL) { 1122fcf59617SAndrey V. Elsukov switch (sp->req[i]->saidx.dst.sa.sa_family) { 1123fcf59617SAndrey V. Elsukov #ifdef INET 112488768458SSam Leffler case AF_INET: 1125fcf59617SAndrey V. Elsukov size += sizeof(struct ip); 112688768458SSam Leffler break; 1127fcf59617SAndrey V. Elsukov #endif 112888768458SSam Leffler #ifdef INET6 112988768458SSam Leffler case AF_INET6: 1130fcf59617SAndrey V. Elsukov size += sizeof(struct ip6_hdr); 113188768458SSam Leffler break; 113288768458SSam Leffler #endif 113388768458SSam Leffler default: 11349ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 11359ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 1136fcf59617SAndrey V. Elsukov sp->req[i]->saidx.dst.sa.sa_family)); 113788768458SSam Leffler break; 113888768458SSam Leffler } 113988768458SSam Leffler } 114088768458SSam Leffler } 11411f8bd75eSBjoern A. Zeeb return (size); 114288768458SSam Leffler } 114388768458SSam Leffler 114497aa4a51SBjoern A. Zeeb /* 1145fcf59617SAndrey V. Elsukov * Compute ESP/AH header size for protocols with PCB, including 1146fcf59617SAndrey V. Elsukov * outer IP header. Currently only tcp_output() uses it. 114797aa4a51SBjoern A. Zeeb */ 114888768458SSam Leffler size_t 1149fcf59617SAndrey V. Elsukov ipsec_hdrsiz_inpcb(struct inpcb *inp) 115088768458SSam Leffler { 1151fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 115288768458SSam Leffler struct secpolicy *sp; 1153fcf59617SAndrey V. Elsukov size_t sz; 115488768458SSam Leffler 1155fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, IPSEC_DIR_OUTBOUND); 1156fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(IPSEC_DIR_OUTBOUND)) { 1157fcf59617SAndrey V. Elsukov ipsec_setspidx_inpcb(inp, &spidx, IPSEC_DIR_OUTBOUND); 1158fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, IPSEC_DIR_OUTBOUND); 115988768458SSam Leffler } 1160fcf59617SAndrey V. Elsukov if (sp == NULL) 1161fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 1162fcf59617SAndrey V. Elsukov sz = ipsec_hdrsiz_internal(sp); 1163fcf59617SAndrey V. Elsukov key_freesp(&sp); 1164fcf59617SAndrey V. Elsukov return (sz); 116588768458SSam Leffler } 116688768458SSam Leffler 116788768458SSam Leffler /* 116888768458SSam Leffler * Check the variable replay window. 116988768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 117088768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 117188768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 117288768458SSam Leffler * beforehand). 117388768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 117488768458SSam Leffler * 1175bf435626SFabien Thomas * Based on RFC 6479. Blocks are 32 bits unsigned integers 117688768458SSam Leffler */ 1177bf435626SFabien Thomas 1178bf435626SFabien Thomas #define IPSEC_BITMAP_INDEX_MASK(w) (w - 1) 1179bf435626SFabien Thomas #define IPSEC_REDUNDANT_BIT_SHIFTS 5 1180bf435626SFabien Thomas #define IPSEC_REDUNDANT_BITS (1 << IPSEC_REDUNDANT_BIT_SHIFTS) 1181bf435626SFabien Thomas #define IPSEC_BITMAP_LOC_MASK (IPSEC_REDUNDANT_BITS - 1) 1182bf435626SFabien Thomas 118388768458SSam Leffler int 1184fcf59617SAndrey V. Elsukov ipsec_chkreplay(uint32_t seq, struct secasvar *sav) 118588768458SSam Leffler { 118688768458SSam Leffler const struct secreplay *replay; 1187fcf59617SAndrey V. Elsukov uint32_t wsizeb; /* Constant: window size. */ 1188fcf59617SAndrey V. Elsukov int index, bit_location; 118988768458SSam Leffler 11909ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 11919ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 119288768458SSam Leffler 119388768458SSam Leffler replay = sav->replay; 119488768458SSam Leffler 1195bf435626SFabien Thomas /* No need to check replay if disabled. */ 119688768458SSam Leffler if (replay->wsize == 0) 1197fcf59617SAndrey V. Elsukov return (1); 119888768458SSam Leffler 1199de47c390SBjoern A. Zeeb /* Constant. */ 120088768458SSam Leffler wsizeb = replay->wsize << 3; 120188768458SSam Leffler 1202de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 120388768458SSam Leffler if (seq == 0) 1204fcf59617SAndrey V. Elsukov return (0); 120588768458SSam Leffler 1206de47c390SBjoern A. Zeeb /* First time is always okay. */ 120788768458SSam Leffler if (replay->count == 0) 1208fcf59617SAndrey V. Elsukov return (1); 120988768458SSam Leffler 1210de47c390SBjoern A. Zeeb /* Larger sequences are okay. */ 1211bf435626SFabien Thomas if (seq > replay->lastseq) 1212fcf59617SAndrey V. Elsukov return (1); 121388768458SSam Leffler 1214de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 1215bf435626SFabien Thomas if (replay->lastseq - seq >= wsizeb) 1216fcf59617SAndrey V. Elsukov return (0); 121788768458SSam Leffler 1218bf435626SFabien Thomas /* The sequence is inside the sliding window 1219bf435626SFabien Thomas * now check the bit in the bitmap 1220bf435626SFabien Thomas * bit location only depends on the sequence number 1221bf435626SFabien Thomas */ 1222bf435626SFabien Thomas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 1223bf435626SFabien Thomas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS) 1224bf435626SFabien Thomas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 122588768458SSam Leffler 1226de47c390SBjoern A. Zeeb /* This packet already seen? */ 1227bf435626SFabien Thomas if ((replay->bitmap)[index] & (1 << bit_location)) 1228fcf59617SAndrey V. Elsukov return (0); 1229fcf59617SAndrey V. Elsukov return (1); 123088768458SSam Leffler } 123188768458SSam Leffler 123288768458SSam Leffler /* 1233de47c390SBjoern A. Zeeb * Check replay counter whether to update or not. 123488768458SSam Leffler * OUT: 0: OK 123588768458SSam Leffler * 1: NG 123688768458SSam Leffler */ 123788768458SSam Leffler int 1238fcf59617SAndrey V. Elsukov ipsec_updatereplay(uint32_t seq, struct secasvar *sav) 123988768458SSam Leffler { 1240962ac6c7SAndrey V. Elsukov char buf[128]; 124188768458SSam Leffler struct secreplay *replay; 1242fcf59617SAndrey V. Elsukov uint32_t wsizeb; /* Constant: window size. */ 1243fcf59617SAndrey V. Elsukov int diff, index, bit_location; 124488768458SSam Leffler 12459ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 12469ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 124788768458SSam Leffler 124888768458SSam Leffler replay = sav->replay; 124988768458SSam Leffler 125088768458SSam Leffler if (replay->wsize == 0) 1251de47c390SBjoern A. Zeeb goto ok; /* No need to check replay. */ 125288768458SSam Leffler 1253de47c390SBjoern A. Zeeb /* Constant. */ 125488768458SSam Leffler wsizeb = replay->wsize << 3; 125588768458SSam Leffler 1256de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 125788768458SSam Leffler if (seq == 0) 1258fcf59617SAndrey V. Elsukov return (1); 125988768458SSam Leffler 1260bf435626SFabien Thomas /* The packet is too old, no need to update */ 1261bf435626SFabien Thomas if (wsizeb + seq < replay->lastseq) 126288768458SSam Leffler goto ok; 126388768458SSam Leffler 1264bf435626SFabien Thomas /* Now update the bit */ 1265bf435626SFabien Thomas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS); 1266bf435626SFabien Thomas 1267bf435626SFabien Thomas /* First check if the sequence number is in the range */ 126888768458SSam Leffler if (seq > replay->lastseq) { 1269bf435626SFabien Thomas int id; 1270bf435626SFabien Thomas int index_cur = replay->lastseq >> IPSEC_REDUNDANT_BIT_SHIFTS; 127188768458SSam Leffler 1272bf435626SFabien Thomas diff = index - index_cur; 1273bf435626SFabien Thomas if (diff > replay->bitmap_size) { 1274bf435626SFabien Thomas /* something unusual in this case */ 1275bf435626SFabien Thomas diff = replay->bitmap_size; 127688768458SSam Leffler } 1277bf435626SFabien Thomas 1278bf435626SFabien Thomas for (id = 0; id < diff; ++id) { 1279bf435626SFabien Thomas replay->bitmap[(id + index_cur + 1) 1280bf435626SFabien Thomas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size)] = 0; 1281bf435626SFabien Thomas } 1282bf435626SFabien Thomas 128388768458SSam Leffler replay->lastseq = seq; 128488768458SSam Leffler } 128588768458SSam Leffler 1286bf435626SFabien Thomas index &= IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 1287bf435626SFabien Thomas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 1288bf435626SFabien Thomas 1289bf435626SFabien Thomas /* this packet has already been received */ 1290bf435626SFabien Thomas if (replay->bitmap[index] & (1 << bit_location)) 1291fcf59617SAndrey V. Elsukov return (1); 1292bf435626SFabien Thomas 1293bf435626SFabien Thomas replay->bitmap[index] |= (1 << bit_location); 1294bf435626SFabien Thomas 129588768458SSam Leffler ok: 129688768458SSam Leffler if (replay->count == ~0) { 129788768458SSam Leffler 1298de47c390SBjoern A. Zeeb /* Set overflow flag. */ 129988768458SSam Leffler replay->overflow++; 130088768458SSam Leffler 1301de47c390SBjoern A. Zeeb /* Don't increment, no more packets accepted. */ 1302fcf59617SAndrey V. Elsukov if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { 1303fcf59617SAndrey V. Elsukov if (sav->sah->saidx.proto == IPPROTO_AH) 1304fcf59617SAndrey V. Elsukov AHSTAT_INC(ahs_wrap); 1305fcf59617SAndrey V. Elsukov else if (sav->sah->saidx.proto == IPPROTO_ESP) 1306fcf59617SAndrey V. Elsukov ESPSTAT_INC(esps_wrap); 1307fcf59617SAndrey V. Elsukov return (1); 1308fcf59617SAndrey V. Elsukov } 130988768458SSam Leffler 13109ffa9677SSam Leffler ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 1311962ac6c7SAndrey V. Elsukov __func__, replay->overflow, 1312fcf59617SAndrey V. Elsukov ipsec_sa2str(sav, buf, sizeof(buf)))); 1313fcf59617SAndrey V. Elsukov } 1314fcf59617SAndrey V. Elsukov return (0); 131588768458SSam Leffler } 131688768458SSam Leffler 1317fcf59617SAndrey V. Elsukov int 1318fcf59617SAndrey V. Elsukov ipsec_updateid(struct secasvar *sav, uint64_t *new, uint64_t *old) 1319fcf59617SAndrey V. Elsukov { 1320fcf59617SAndrey V. Elsukov uint64_t tmp; 132188768458SSam Leffler 1322fcf59617SAndrey V. Elsukov /* 1323fcf59617SAndrey V. Elsukov * tdb_cryptoid is initialized by xform_init(). 1324fcf59617SAndrey V. Elsukov * Then it can be changed only when some crypto error occurred or 1325fcf59617SAndrey V. Elsukov * when SA is deleted. We stored used cryptoid in the xform_data 1326fcf59617SAndrey V. Elsukov * structure. In case when crypto error occurred and crypto 1327fcf59617SAndrey V. Elsukov * subsystem has reinited the session, it returns new cryptoid 1328fcf59617SAndrey V. Elsukov * and EAGAIN error code. 1329fcf59617SAndrey V. Elsukov * 1330fcf59617SAndrey V. Elsukov * This function will be called when we got EAGAIN from crypto 1331fcf59617SAndrey V. Elsukov * subsystem. 1332fcf59617SAndrey V. Elsukov * *new is cryptoid that was returned by crypto subsystem in 1333fcf59617SAndrey V. Elsukov * the crp_sid. 1334fcf59617SAndrey V. Elsukov * *old is the original cryptoid that we stored in xform_data. 1335fcf59617SAndrey V. Elsukov * 1336fcf59617SAndrey V. Elsukov * For first failed request *old == sav->tdb_cryptoid, then 1337fcf59617SAndrey V. Elsukov * we update sav->tdb_cryptoid and redo crypto_dispatch(). 1338fcf59617SAndrey V. Elsukov * For next failed request *old != sav->tdb_cryptoid, then 1339fcf59617SAndrey V. Elsukov * we store cryptoid from first request into the *new variable 1340fcf59617SAndrey V. Elsukov * and crp_sid from this second session will be returned via 1341fcf59617SAndrey V. Elsukov * *old pointer, so caller can release second session. 1342fcf59617SAndrey V. Elsukov * 1343fcf59617SAndrey V. Elsukov * XXXAE: check this more carefully. 1344fcf59617SAndrey V. Elsukov */ 1345fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 1346fcf59617SAndrey V. Elsukov printf("%s: SA(%p) moves cryptoid %jd -> %jd\n", 1347fcf59617SAndrey V. Elsukov __func__, sav, (uintmax_t)(*old), (uintmax_t)(*new))); 1348fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secasv(sav)); 1349fcf59617SAndrey V. Elsukov SECASVAR_LOCK(sav); 1350fcf59617SAndrey V. Elsukov if (sav->tdb_cryptoid != *old) { 1351fcf59617SAndrey V. Elsukov /* cryptoid was already updated */ 1352fcf59617SAndrey V. Elsukov tmp = *new; 1353fcf59617SAndrey V. Elsukov *new = sav->tdb_cryptoid; 1354fcf59617SAndrey V. Elsukov *old = tmp; 1355bf435626SFabien Thomas SECASVAR_UNLOCK(sav); 1356fcf59617SAndrey V. Elsukov return (1); 1357fcf59617SAndrey V. Elsukov } 1358fcf59617SAndrey V. Elsukov sav->tdb_cryptoid = *new; 1359fcf59617SAndrey V. Elsukov SECASVAR_UNLOCK(sav); 1360fcf59617SAndrey V. Elsukov return (0); 136188768458SSam Leffler } 136288768458SSam Leffler 1363fcf59617SAndrey V. Elsukov int 1364fcf59617SAndrey V. Elsukov ipsec_initialized(void) 136588768458SSam Leffler { 1366de47c390SBjoern A. Zeeb 1367fcf59617SAndrey V. Elsukov return (V_def_policy != NULL); 136888768458SSam Leffler } 136988768458SSam Leffler 13708381996eSSam Leffler static void 137193201211SAndrey V. Elsukov def_policy_init(const void *unused __unused) 13721ed81b73SMarko Zec { 13731ed81b73SMarko Zec 1374fcf59617SAndrey V. Elsukov V_def_policy = key_newsp(); 1375fcf59617SAndrey V. Elsukov if (V_def_policy != NULL) { 1376fcf59617SAndrey V. Elsukov V_def_policy->policy = IPSEC_POLICY_NONE; 1377fcf59617SAndrey V. Elsukov /* Force INPCB SP cache invalidation */ 1378fcf59617SAndrey V. Elsukov key_bumpspgen(); 1379fcf59617SAndrey V. Elsukov } else 1380fcf59617SAndrey V. Elsukov printf("%s: failed to initialize default policy\n", __func__); 13818381996eSSam Leffler } 1382fcf59617SAndrey V. Elsukov 1383fcf59617SAndrey V. Elsukov 1384fcf59617SAndrey V. Elsukov static void 1385fcf59617SAndrey V. Elsukov def_policy_uninit(const void *unused __unused) 1386fcf59617SAndrey V. Elsukov { 1387fcf59617SAndrey V. Elsukov 1388fcf59617SAndrey V. Elsukov if (V_def_policy != NULL) { 1389fcf59617SAndrey V. Elsukov key_freesp(&V_def_policy); 1390fcf59617SAndrey V. Elsukov key_bumpspgen(); 1391fcf59617SAndrey V. Elsukov } 1392fcf59617SAndrey V. Elsukov } 1393fcf59617SAndrey V. Elsukov 139489856f7eSBjoern A. Zeeb VNET_SYSINIT(def_policy_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 139593201211SAndrey V. Elsukov def_policy_init, NULL); 1396fcf59617SAndrey V. Elsukov VNET_SYSUNINIT(def_policy_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 1397fcf59617SAndrey V. Elsukov def_policy_uninit, NULL); 1398