188768458SSam Leffler /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ 288768458SSam Leffler 3c398230bSWarner Losh /*- 451369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 551369649SPedro F. Giffuni * 688768458SSam Leffler * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 788768458SSam Leffler * All rights reserved. 888768458SSam Leffler * 988768458SSam Leffler * Redistribution and use in source and binary forms, with or without 1088768458SSam Leffler * modification, are permitted provided that the following conditions 1188768458SSam Leffler * are met: 1288768458SSam Leffler * 1. Redistributions of source code must retain the above copyright 1388768458SSam Leffler * notice, this list of conditions and the following disclaimer. 1488768458SSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 1588768458SSam Leffler * notice, this list of conditions and the following disclaimer in the 1688768458SSam Leffler * documentation and/or other materials provided with the distribution. 1788768458SSam Leffler * 3. Neither the name of the project nor the names of its contributors 1888768458SSam Leffler * may be used to endorse or promote products derived from this software 1988768458SSam Leffler * without specific prior written permission. 2088768458SSam Leffler * 2188768458SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2288768458SSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2388768458SSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2488768458SSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2588768458SSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2688768458SSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2788768458SSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2888768458SSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2988768458SSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3088768458SSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3188768458SSam Leffler * SUCH DAMAGE. 3288768458SSam Leffler */ 3388768458SSam Leffler 3488768458SSam Leffler /* 3588768458SSam Leffler * IPsec controller part. 3688768458SSam Leffler */ 3788768458SSam Leffler 3888768458SSam Leffler #include "opt_inet.h" 3988768458SSam Leffler #include "opt_inet6.h" 4088768458SSam Leffler #include "opt_ipsec.h" 4188768458SSam Leffler 4288768458SSam Leffler #include <sys/param.h> 4388768458SSam Leffler #include <sys/systm.h> 4488768458SSam Leffler #include <sys/malloc.h> 4588768458SSam Leffler #include <sys/mbuf.h> 4688768458SSam Leffler #include <sys/domain.h> 4746ee43b2SRobert Watson #include <sys/priv.h> 4888768458SSam Leffler #include <sys/protosw.h> 4988768458SSam Leffler #include <sys/socket.h> 5088768458SSam Leffler #include <sys/socketvar.h> 5188768458SSam Leffler #include <sys/errno.h> 52ef91a976SAndrey V. Elsukov #include <sys/hhook.h> 5388768458SSam Leffler #include <sys/time.h> 5488768458SSam Leffler #include <sys/kernel.h> 5588768458SSam Leffler #include <sys/syslog.h> 5688768458SSam Leffler #include <sys/sysctl.h> 5788768458SSam Leffler #include <sys/proc.h> 5888768458SSam Leffler 5988768458SSam Leffler #include <net/if.h> 60ef91a976SAndrey V. Elsukov #include <net/if_enc.h> 6176039bc8SGleb Smirnoff #include <net/if_var.h> 62eddfbb76SRobert Watson #include <net/vnet.h> 6388768458SSam Leffler 6488768458SSam Leffler #include <netinet/in.h> 6588768458SSam Leffler #include <netinet/in_systm.h> 6688768458SSam Leffler #include <netinet/ip.h> 6788768458SSam Leffler #include <netinet/ip_var.h> 6888768458SSam Leffler #include <netinet/in_var.h> 6988768458SSam Leffler #include <netinet/udp.h> 7088768458SSam Leffler #include <netinet/udp_var.h> 7188768458SSam Leffler #include <netinet/tcp.h> 7288768458SSam Leffler #include <netinet/udp.h> 7388768458SSam Leffler 7488768458SSam Leffler #include <netinet/ip6.h> 7588768458SSam Leffler #ifdef INET6 7688768458SSam Leffler #include <netinet6/ip6_var.h> 7788768458SSam Leffler #endif 7888768458SSam Leffler #include <netinet/in_pcb.h> 7988768458SSam Leffler #ifdef INET6 8088768458SSam Leffler #include <netinet/icmp6.h> 8188768458SSam Leffler #endif 8288768458SSam Leffler 832cb64cb2SGeorge V. Neville-Neil #include <sys/types.h> 8488768458SSam Leffler #include <netipsec/ipsec.h> 8588768458SSam Leffler #ifdef INET6 8688768458SSam Leffler #include <netipsec/ipsec6.h> 8788768458SSam Leffler #endif 88ef2a572bSKonstantin Belousov #include <netipsec/ipsec_offload.h> 8988768458SSam Leffler #include <netipsec/ah_var.h> 9088768458SSam Leffler #include <netipsec/esp_var.h> 9188768458SSam Leffler #include <netipsec/ipcomp.h> /*XXX*/ 9288768458SSam Leffler #include <netipsec/ipcomp_var.h> 93fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h> 9488768458SSam Leffler 9588768458SSam Leffler #include <netipsec/key.h> 9688768458SSam Leffler #include <netipsec/keydb.h> 9788768458SSam Leffler #include <netipsec/key_debug.h> 9888768458SSam Leffler 9988768458SSam Leffler #include <netipsec/xform.h> 10088768458SSam Leffler 10188768458SSam Leffler #include <machine/in_cksum.h> 10288768458SSam Leffler 1037aee3dd1SSam Leffler #include <opencrypto/cryptodev.h> 1047aee3dd1SSam Leffler 105de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */ 106db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec4stat); 107db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec4stat); 108db8c0879SAndrey V. Elsukov 109db8c0879SAndrey V. Elsukov #ifdef VIMAGE 110db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec4stat); 111db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 112db8c0879SAndrey V. Elsukov 113eddfbb76SRobert Watson /* DF bit on encap. 0: clear 1: set 2: copy */ 114eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_dfbit) = 0; 115d9d59bb1SWojciech Macek VNET_DEFINE(int, ip4_ipsec_min_pmtu) = 576; 116eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE; 117eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE; 118eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE; 119eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE; 120eddfbb76SRobert Watson /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 121eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_ecn) = 0; 122*70703aa9Sacazuc VNET_DEFINE(int, ip4_ipsec_random_id) = 0; 123eddfbb76SRobert Watson 1245f901c92SAndrew Turner VNET_DEFINE_STATIC(int, ip4_filtertunnel) = 0; 125fcf59617SAndrey V. Elsukov #define V_ip4_filtertunnel VNET(ip4_filtertunnel) 1265f901c92SAndrew Turner VNET_DEFINE_STATIC(int, check_policy_history) = 0; 127fcf59617SAndrey V. Elsukov #define V_check_policy_history VNET(check_policy_history) 1285f901c92SAndrew Turner VNET_DEFINE_STATIC(struct secpolicy *, def_policy) = NULL; 12993201211SAndrey V. Elsukov #define V_def_policy VNET(def_policy) 130fcf59617SAndrey V. Elsukov static int 131fcf59617SAndrey V. Elsukov sysctl_def_policy(SYSCTL_HANDLER_ARGS) 132fcf59617SAndrey V. Elsukov { 133fcf59617SAndrey V. Elsukov int error, value; 134fcf59617SAndrey V. Elsukov 135fcf59617SAndrey V. Elsukov value = V_def_policy->policy; 136fcf59617SAndrey V. Elsukov error = sysctl_handle_int(oidp, &value, 0, req); 137fcf59617SAndrey V. Elsukov if (error == 0) { 138fcf59617SAndrey V. Elsukov if (value != IPSEC_POLICY_DISCARD && 139fcf59617SAndrey V. Elsukov value != IPSEC_POLICY_NONE) 140fcf59617SAndrey V. Elsukov return (EINVAL); 141fcf59617SAndrey V. Elsukov V_def_policy->policy = value; 142fcf59617SAndrey V. Elsukov } 143fcf59617SAndrey V. Elsukov return (error); 144fcf59617SAndrey V. Elsukov } 145fcf59617SAndrey V. Elsukov 14688768458SSam Leffler /* 14788768458SSam Leffler * Crypto support requirements: 14888768458SSam Leffler * 14988768458SSam Leffler * 1 require hardware support 15088768458SSam Leffler * -1 require software support 15188768458SSam Leffler * 0 take anything 15288768458SSam Leffler */ 153eddfbb76SRobert Watson VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 15439bbca6fSFabien Thomas 15539bbca6fSFabien Thomas /* 15639bbca6fSFabien Thomas * Use asynchronous mode to parallelize crypto jobs: 15739bbca6fSFabien Thomas * 15839bbca6fSFabien Thomas * 0 - disabled 15939bbca6fSFabien Thomas * 1 - enabled 16039bbca6fSFabien Thomas */ 16139bbca6fSFabien Thomas VNET_DEFINE(int, async_crypto) = 0; 16239bbca6fSFabien Thomas 163fcf59617SAndrey V. Elsukov /* 164fcf59617SAndrey V. Elsukov * TCP/UDP checksum handling policy for transport mode NAT-T (RFC3948) 165fcf59617SAndrey V. Elsukov * 166fcf59617SAndrey V. Elsukov * 0 - auto: incrementally recompute, when checksum delta is known; 167fcf59617SAndrey V. Elsukov * if checksum delta isn't known, reset checksum to zero for UDP, 168fcf59617SAndrey V. Elsukov * and mark csum_flags as valid for TCP. 169fcf59617SAndrey V. Elsukov * 1 - fully recompute TCP/UDP checksum. 170fcf59617SAndrey V. Elsukov */ 171fcf59617SAndrey V. Elsukov VNET_DEFINE(int, natt_cksum_policy) = 0; 17288768458SSam Leffler 17313a6cf24SBjoern A. Zeeb FEATURE(ipsec, "Internet Protocol Security (IPsec)"); 17413a6cf24SBjoern A. Zeeb FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')"); 17513a6cf24SBjoern A. Zeeb 17688768458SSam Leffler /* net.inet.ipsec */ 177fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, 1787029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1797029da5cSPawel Biernacki 0, 0, sysctl_def_policy, "I", 180be6b1304STom Rhodes "IPsec default policy."); 1816df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1826df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0, 1838b615593SMarko Zec "Default ESP transport mode level"); 1846df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1856df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0, 1868b615593SMarko Zec "Default ESP tunnel mode level."); 1876df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1886df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0, 1898b615593SMarko Zec "AH transfer mode default level."); 1906df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 1916df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0, 1928b615593SMarko Zec "AH tunnel mode default level."); 1936df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, 1946df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, 195fcf59617SAndrey V. Elsukov "If set, clear type-of-service field when doing AH computation."); 1966df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit, 1976df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0, 1988b615593SMarko Zec "Do not fragment bit on encap."); 199d9d59bb1SWojciech Macek SYSCTL_INT(_net_inet_ipsec, IPSECCTL_MIN_PMTU, min_pmtu, 200d9d59bb1SWojciech Macek CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_min_pmtu), 0, 201d9d59bb1SWojciech Macek "Lowest acceptable PMTU value."); 2026df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, 2036df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0, 204be6b1304STom Rhodes "Explicit Congestion Notification handling."); 205*70703aa9Sacazuc SYSCTL_INT(_net_inet_ipsec, IPSECCTL_RANDOM_ID, random_id, 206*70703aa9Sacazuc CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_random_id), 0, 207*70703aa9Sacazuc "Assign random ip_id values."); 2086df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support, 2096df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0, 210be6b1304STom Rhodes "Crypto driver selection."); 21139bbca6fSFabien Thomas SYSCTL_INT(_net_inet_ipsec, OID_AUTO, async_crypto, 21239bbca6fSFabien Thomas CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(async_crypto), 0, 21339bbca6fSFabien Thomas "Use asynchronous mode to parallelize crypto jobs."); 214fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, check_policy_history, 215fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(check_policy_history), 0, 216fcf59617SAndrey V. Elsukov "Use strict check of inbound packets to security policy compliance."); 217fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, natt_cksum_policy, 218fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(natt_cksum_policy), 0, 219fcf59617SAndrey V. Elsukov "Method to fix TCP/UDP checksum for transport mode IPsec after NAT."); 220fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet_ipsec, OID_AUTO, filtertunnel, 221fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_filtertunnel), 0, 222fcf59617SAndrey V. Elsukov "If set, filter packets from an IPsec tunnel."); 223db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat, 224db8c0879SAndrey V. Elsukov ipsec4stat, "IPsec IPv4 statistics."); 22588768458SSam Leffler 2266131838bSPawel Jakub Dawidek #ifdef REGRESSION 227dfa9422bSPawel Jakub Dawidek /* 228dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 229dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 230dfa9422bSPawel Jakub Dawidek */ 231eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_replay) = 0; 2326df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, 2336df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0, 234eddfbb76SRobert Watson "Emulate replay attack"); 235dfa9422bSPawel Jakub Dawidek /* 236dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 237dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 238dfa9422bSPawel Jakub Dawidek */ 239eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_integrity) = 0; 2406df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, 2416df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0, 242eddfbb76SRobert Watson "Emulate man-in-the-middle attack"); 2436131838bSPawel Jakub Dawidek #endif 244dfa9422bSPawel Jakub Dawidek 24588768458SSam Leffler #ifdef INET6 246db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec6stat); 247db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec6stat); 248db8c0879SAndrey V. Elsukov 249db8c0879SAndrey V. Elsukov #ifdef VIMAGE 250db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec6stat); 251db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 252db8c0879SAndrey V. Elsukov 253eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE; 254eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE; 255eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE; 256eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE; 257eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ipsec_ecn) = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 25888768458SSam Leffler 2595f901c92SAndrew Turner VNET_DEFINE_STATIC(int, ip6_filtertunnel) = 0; 260fcf59617SAndrey V. Elsukov #define V_ip6_filtertunnel VNET(ip6_filtertunnel) 261fcf59617SAndrey V. Elsukov 26288768458SSam Leffler /* net.inet6.ipsec6 */ 263fcf59617SAndrey V. Elsukov SYSCTL_PROC(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, 2647029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 2657029da5cSPawel Biernacki 0, 0, sysctl_def_policy, "I", 2668b615593SMarko Zec "IPsec default policy."); 2676df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 2686df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0, 2698b615593SMarko Zec "Default ESP transport mode level."); 2706df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 2716df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0, 2728b615593SMarko Zec "Default ESP tunnel mode level."); 2736df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 2746df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0, 2758b615593SMarko Zec "AH transfer mode default level."); 2766df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 2776df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0, 2788b615593SMarko Zec "AH tunnel mode default level."); 2796df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, 2806df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0, 2813377c961STom Rhodes "Explicit Congestion Notification handling."); 282fcf59617SAndrey V. Elsukov SYSCTL_INT(_net_inet6_ipsec6, OID_AUTO, filtertunnel, 283fcf59617SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_filtertunnel), 0, 284fcf59617SAndrey V. Elsukov "If set, filter packets from an IPsec tunnel."); 285db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats, 286db8c0879SAndrey V. Elsukov struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics."); 28788768458SSam Leffler #endif /* INET6 */ 28888768458SSam Leffler 289fcf59617SAndrey V. Elsukov static int ipsec_in_reject(struct secpolicy *, struct inpcb *, 290fcf59617SAndrey V. Elsukov const struct mbuf *); 291fcf59617SAndrey V. Elsukov 292fcf59617SAndrey V. Elsukov #ifdef INET 2930ff2d00dSKonstantin Belousov static void ipsec4_get_ulp(const struct mbuf *, const struct ip *, 2940ff2d00dSKonstantin Belousov struct secpolicyindex *, int); 2950ff2d00dSKonstantin Belousov static void ipsec4_setspidx_ipaddr(const struct mbuf *, struct ip *, 296fcf59617SAndrey V. Elsukov struct secpolicyindex *); 297fcf59617SAndrey V. Elsukov #endif 29888768458SSam Leffler #ifdef INET6 299efb10c3cSAndrey V. Elsukov static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); 300fcf59617SAndrey V. Elsukov static void ipsec6_setspidx_ipaddr(const struct mbuf *, 301fcf59617SAndrey V. Elsukov struct secpolicyindex *); 30288768458SSam Leffler #endif 3036464079fSSam Leffler 30488768458SSam Leffler /* 30588768458SSam Leffler * Return a held reference to the default SP. 30688768458SSam Leffler */ 30788768458SSam Leffler static struct secpolicy * 308fcf59617SAndrey V. Elsukov key_allocsp_default(void) 309fcf59617SAndrey V. Elsukov { 310fcf59617SAndrey V. Elsukov 311fcf59617SAndrey V. Elsukov key_addref(V_def_policy); 312fcf59617SAndrey V. Elsukov return (V_def_policy); 313fcf59617SAndrey V. Elsukov } 314fcf59617SAndrey V. Elsukov 315fcf59617SAndrey V. Elsukov static void 316fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(struct inpcb *inp, u_int dir) 31788768458SSam Leffler { 31888768458SSam Leffler struct secpolicy *sp; 31988768458SSam Leffler 320fcf59617SAndrey V. Elsukov INP_WLOCK_ASSERT(inp); 321fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 322fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_INBOUND_POLICY) 323fcf59617SAndrey V. Elsukov return; 324fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_in; 325fcf59617SAndrey V. Elsukov inp->inp_sp->sp_in = NULL; 326fcf59617SAndrey V. Elsukov } else { 327fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_OUTBOUND_POLICY) 328fcf59617SAndrey V. Elsukov return; 329fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_out; 330fcf59617SAndrey V. Elsukov inp->inp_sp->sp_out = NULL; 33188768458SSam Leffler } 332fcf59617SAndrey V. Elsukov if (sp != NULL) 333fcf59617SAndrey V. Elsukov key_freesp(&sp); /* release extra reference */ 33488768458SSam Leffler } 33588768458SSam Leffler 336fcf59617SAndrey V. Elsukov static void 337fcf59617SAndrey V. Elsukov ipsec_cachepolicy(struct inpcb *inp, struct secpolicy *sp, u_int dir) 338fcf59617SAndrey V. Elsukov { 339fcf59617SAndrey V. Elsukov uint32_t genid; 340fcf59617SAndrey V. Elsukov int downgrade; 341fcf59617SAndrey V. Elsukov 342fcf59617SAndrey V. Elsukov INP_LOCK_ASSERT(inp); 343fcf59617SAndrey V. Elsukov 344fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 345fcf59617SAndrey V. Elsukov /* Do we have configured PCB policy? */ 346fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_OUTBOUND_POLICY) 347fcf59617SAndrey V. Elsukov return; 348fcf59617SAndrey V. Elsukov /* Another thread has already set cached policy */ 349fcf59617SAndrey V. Elsukov if (inp->inp_sp->sp_out != NULL) 350fcf59617SAndrey V. Elsukov return; 35188768458SSam Leffler /* 352fcf59617SAndrey V. Elsukov * Do not cache OUTBOUND policy if PCB isn't connected, 353fcf59617SAndrey V. Elsukov * i.e. foreign address is INADDR_ANY/UNSPECIFIED. 35488768458SSam Leffler */ 355fcf59617SAndrey V. Elsukov #ifdef INET 356fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV4) != 0 && 357fcf59617SAndrey V. Elsukov inp->inp_faddr.s_addr == INADDR_ANY) 358fcf59617SAndrey V. Elsukov return; 359fcf59617SAndrey V. Elsukov #endif 360fcf59617SAndrey V. Elsukov #ifdef INET6 361fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV6) != 0 && 362fcf59617SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 363fcf59617SAndrey V. Elsukov return; 364fcf59617SAndrey V. Elsukov #endif 365fcf59617SAndrey V. Elsukov } else { 366fcf59617SAndrey V. Elsukov /* Do we have configured PCB policy? */ 367fcf59617SAndrey V. Elsukov if (inp->inp_sp->flags & INP_INBOUND_POLICY) 368fcf59617SAndrey V. Elsukov return; 369fcf59617SAndrey V. Elsukov /* Another thread has already set cached policy */ 370fcf59617SAndrey V. Elsukov if (inp->inp_sp->sp_in != NULL) 371fcf59617SAndrey V. Elsukov return; 37288768458SSam Leffler /* 373fcf59617SAndrey V. Elsukov * Do not cache INBOUND policy for listen socket, 374fcf59617SAndrey V. Elsukov * that is bound to INADDR_ANY/UNSPECIFIED address. 37588768458SSam Leffler */ 376fcf59617SAndrey V. Elsukov #ifdef INET 377fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV4) != 0 && 378fcf59617SAndrey V. Elsukov inp->inp_faddr.s_addr == INADDR_ANY) 379fcf59617SAndrey V. Elsukov return; 380fcf59617SAndrey V. Elsukov #endif 381fcf59617SAndrey V. Elsukov #ifdef INET6 382fcf59617SAndrey V. Elsukov if ((inp->inp_vflag & INP_IPV6) != 0 && 383fcf59617SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 384fcf59617SAndrey V. Elsukov return; 385fcf59617SAndrey V. Elsukov #endif 386c1fc5e96SErmal Luçi } 387fcf59617SAndrey V. Elsukov downgrade = 0; 388fcf59617SAndrey V. Elsukov if (!INP_WLOCKED(inp)) { 389fcf59617SAndrey V. Elsukov if ((downgrade = INP_TRY_UPGRADE(inp)) == 0) 390fcf59617SAndrey V. Elsukov return; 39188768458SSam Leffler } 392fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) 393fcf59617SAndrey V. Elsukov inp->inp_sp->sp_out = sp; 39488768458SSam Leffler else 395fcf59617SAndrey V. Elsukov inp->inp_sp->sp_in = sp; 396fcf59617SAndrey V. Elsukov /* 397fcf59617SAndrey V. Elsukov * SP is already referenced by the lookup code. 398fcf59617SAndrey V. Elsukov * We take extra reference here to avoid race in the 399fcf59617SAndrey V. Elsukov * ipsec_getpcbpolicy() function - SP will not be freed in the 400fcf59617SAndrey V. Elsukov * time between we take SP pointer from the cache and key_addref() 401fcf59617SAndrey V. Elsukov * call. 402fcf59617SAndrey V. Elsukov */ 403fcf59617SAndrey V. Elsukov key_addref(sp); 404fcf59617SAndrey V. Elsukov genid = key_getspgen(); 405fcf59617SAndrey V. Elsukov if (genid != inp->inp_sp->genid) { 406fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, dir); 407fcf59617SAndrey V. Elsukov inp->inp_sp->genid = genid; 40888768458SSam Leffler } 409fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 410fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): cached %s SP(%p)\n", 411fcf59617SAndrey V. Elsukov __func__, inp, dir == IPSEC_DIR_OUTBOUND ? "OUTBOUND": 412fcf59617SAndrey V. Elsukov "INBOUND", sp)); 413fcf59617SAndrey V. Elsukov if (downgrade != 0) 414fcf59617SAndrey V. Elsukov INP_DOWNGRADE(inp); 415fcf59617SAndrey V. Elsukov } 416fcf59617SAndrey V. Elsukov 417fcf59617SAndrey V. Elsukov static struct secpolicy * 418fcf59617SAndrey V. Elsukov ipsec_checkpolicy(struct secpolicy *sp, struct inpcb *inp, int *error) 419fcf59617SAndrey V. Elsukov { 420fcf59617SAndrey V. Elsukov 421fcf59617SAndrey V. Elsukov /* Save found OUTBOUND policy into PCB SP cache. */ 422fcf59617SAndrey V. Elsukov if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_out == NULL) 423fcf59617SAndrey V. Elsukov ipsec_cachepolicy(inp, sp, IPSEC_DIR_OUTBOUND); 424fcf59617SAndrey V. Elsukov 42588768458SSam Leffler switch (sp->policy) { 42688768458SSam Leffler default: 4279ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 428de47c390SBjoern A. Zeeb /* FALLTHROUGH */ 42988768458SSam Leffler case IPSEC_POLICY_DISCARD: 430de47c390SBjoern A. Zeeb *error = -EINVAL; /* Packet is discarded by caller. */ 431fcf59617SAndrey V. Elsukov /* FALLTHROUGH */ 43288768458SSam Leffler case IPSEC_POLICY_BYPASS: 43388768458SSam Leffler case IPSEC_POLICY_NONE: 434fcf59617SAndrey V. Elsukov key_freesp(&sp); 435de47c390SBjoern A. Zeeb sp = NULL; /* NB: force NULL result. */ 43688768458SSam Leffler break; 43788768458SSam Leffler case IPSEC_POLICY_IPSEC: 438fcf59617SAndrey V. Elsukov /* XXXAE: handle LARVAL SP */ 43988768458SSam Leffler break; 44088768458SSam Leffler } 441fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 442fcf59617SAndrey V. Elsukov printf("%s: get SP(%p), error %d\n", __func__, sp, *error)); 443de47c390SBjoern A. Zeeb return (sp); 44488768458SSam Leffler } 44588768458SSam Leffler 446fcf59617SAndrey V. Elsukov static struct secpolicy * 447fcf59617SAndrey V. Elsukov ipsec_getpcbpolicy(struct inpcb *inp, u_int dir) 44888768458SSam Leffler { 449fcf59617SAndrey V. Elsukov struct secpolicy *sp; 450fcf59617SAndrey V. Elsukov int flags, downgrade; 45188768458SSam Leffler 452fcf59617SAndrey V. Elsukov if (inp == NULL || inp->inp_sp == NULL) 453fcf59617SAndrey V. Elsukov return (NULL); 45488768458SSam Leffler 455fcf59617SAndrey V. Elsukov INP_LOCK_ASSERT(inp); 456fcf59617SAndrey V. Elsukov 457fcf59617SAndrey V. Elsukov flags = inp->inp_sp->flags; 458fcf59617SAndrey V. Elsukov if (dir == IPSEC_DIR_OUTBOUND) { 459fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_out; 460fcf59617SAndrey V. Elsukov flags &= INP_OUTBOUND_POLICY; 46188768458SSam Leffler } else { 462fcf59617SAndrey V. Elsukov sp = inp->inp_sp->sp_in; 463fcf59617SAndrey V. Elsukov flags &= INP_INBOUND_POLICY; 46488768458SSam Leffler } 46588768458SSam Leffler /* 466fcf59617SAndrey V. Elsukov * Check flags. If we have PCB SP, just return it. 467fcf59617SAndrey V. Elsukov * Otherwise we need to check that cached SP entry isn't stale. 46888768458SSam Leffler */ 469fcf59617SAndrey V. Elsukov if (flags == 0) { 470fcf59617SAndrey V. Elsukov if (sp == NULL) 471fcf59617SAndrey V. Elsukov return (NULL); 472fcf59617SAndrey V. Elsukov if (inp->inp_sp->genid != key_getspgen()) { 473fcf59617SAndrey V. Elsukov /* Invalidate the cache. */ 474fcf59617SAndrey V. Elsukov downgrade = 0; 475fcf59617SAndrey V. Elsukov if (!INP_WLOCKED(inp)) { 476fcf59617SAndrey V. Elsukov if ((downgrade = INP_TRY_UPGRADE(inp)) == 0) 477fcf59617SAndrey V. Elsukov return (NULL); 478fcf59617SAndrey V. Elsukov } 479fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, IPSEC_DIR_OUTBOUND); 480fcf59617SAndrey V. Elsukov ipsec_invalidate_cache(inp, IPSEC_DIR_INBOUND); 481fcf59617SAndrey V. Elsukov if (downgrade != 0) 482fcf59617SAndrey V. Elsukov INP_DOWNGRADE(inp); 483fcf59617SAndrey V. Elsukov return (NULL); 484fcf59617SAndrey V. Elsukov } 485fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 486fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): cache hit SP(%p)\n", 487fcf59617SAndrey V. Elsukov __func__, inp, sp)); 488fcf59617SAndrey V. Elsukov /* Return referenced cached policy */ 489fcf59617SAndrey V. Elsukov } 490fcf59617SAndrey V. Elsukov key_addref(sp); 491fcf59617SAndrey V. Elsukov return (sp); 49288768458SSam Leffler } 49388768458SSam Leffler 494fcf59617SAndrey V. Elsukov #ifdef INET 49588768458SSam Leffler static void 4960ff2d00dSKonstantin Belousov ipsec4_get_ulp(const struct mbuf *m, const struct ip *ip1, 4970ff2d00dSKonstantin Belousov struct secpolicyindex *spidx, int needport) 49888768458SSam Leffler { 499fcf59617SAndrey V. Elsukov uint8_t nxt; 50088768458SSam Leffler int off; 50188768458SSam Leffler 502de47c390SBjoern A. Zeeb /* Sanity check. */ 503fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip), 504fcf59617SAndrey V. Elsukov ("packet too short")); 50588768458SSam Leffler 5060ff2d00dSKonstantin Belousov if (ip1->ip_off & htons(IP_MF | IP_OFFMASK)) 50788768458SSam Leffler goto done; 5080ff2d00dSKonstantin Belousov off = ip1->ip_hl << 2; 5090ff2d00dSKonstantin Belousov nxt = ip1->ip_p; 51088768458SSam Leffler 51188768458SSam Leffler while (off < m->m_pkthdr.len) { 51288768458SSam Leffler struct ip6_ext ip6e; 51388768458SSam Leffler struct tcphdr th; 51488768458SSam Leffler struct udphdr uh; 51588768458SSam Leffler 51688768458SSam Leffler switch (nxt) { 51788768458SSam Leffler case IPPROTO_TCP: 51888768458SSam Leffler spidx->ul_proto = nxt; 51988768458SSam Leffler if (!needport) 52088768458SSam Leffler goto done_proto; 52188768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 52288768458SSam Leffler goto done; 52388768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 52488768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 52588768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 52688768458SSam Leffler return; 52788768458SSam Leffler case IPPROTO_UDP: 52888768458SSam Leffler spidx->ul_proto = nxt; 52988768458SSam Leffler if (!needport) 53088768458SSam Leffler goto done_proto; 53188768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 53288768458SSam Leffler goto done; 53388768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 53488768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 53588768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 53688768458SSam Leffler return; 53788768458SSam Leffler case IPPROTO_AH: 538afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 53988768458SSam Leffler goto done; 540de47c390SBjoern A. Zeeb /* XXX Sigh, this works but is totally bogus. */ 54188768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 54288768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 54388768458SSam Leffler nxt = ip6e.ip6e_nxt; 54488768458SSam Leffler break; 54588768458SSam Leffler case IPPROTO_ICMP: 54688768458SSam Leffler default: 547de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 54888768458SSam Leffler spidx->ul_proto = nxt; 54988768458SSam Leffler goto done_proto; 55088768458SSam Leffler } 55188768458SSam Leffler } 55288768458SSam Leffler done: 55388768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 55488768458SSam Leffler done_proto: 55588768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 55688768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 557fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 558fcf59617SAndrey V. Elsukov printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL)); 55988768458SSam Leffler } 56088768458SSam Leffler 561fcf59617SAndrey V. Elsukov static void 5620ff2d00dSKonstantin Belousov ipsec4_setspidx_ipaddr(const struct mbuf *m, struct ip *ip1, 5630ff2d00dSKonstantin Belousov struct secpolicyindex *spidx) 56488768458SSam Leffler { 56588768458SSam Leffler 5660ff2d00dSKonstantin Belousov ipsec4_setsockaddrs(m, ip1, &spidx->src, &spidx->dst); 56788768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 56888768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 56988768458SSam Leffler } 57088768458SSam Leffler 571fcf59617SAndrey V. Elsukov static struct secpolicy * 5720ff2d00dSKonstantin Belousov ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, struct ip *ip1, 5730ff2d00dSKonstantin Belousov u_int dir, int needport) 574fcf59617SAndrey V. Elsukov { 575fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 576fcf59617SAndrey V. Elsukov struct secpolicy *sp; 577fcf59617SAndrey V. Elsukov 578fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, dir); 579fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(dir)) { 580fcf59617SAndrey V. Elsukov /* Make an index to look for a policy. */ 5810ff2d00dSKonstantin Belousov ipsec4_setspidx_ipaddr(m, ip1, &spidx); 5820ff2d00dSKonstantin Belousov ipsec4_get_ulp(m, ip1, &spidx, needport); 583fcf59617SAndrey V. Elsukov spidx.dir = dir; 584fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, dir); 585fcf59617SAndrey V. Elsukov } 586fcf59617SAndrey V. Elsukov if (sp == NULL) /* No SP found, use system default. */ 587fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 588fcf59617SAndrey V. Elsukov return (sp); 589fcf59617SAndrey V. Elsukov } 590fcf59617SAndrey V. Elsukov 591fcf59617SAndrey V. Elsukov /* 592fcf59617SAndrey V. Elsukov * Check security policy for *OUTBOUND* IPv4 packet. 593fcf59617SAndrey V. Elsukov */ 594fcf59617SAndrey V. Elsukov struct secpolicy * 5950ff2d00dSKonstantin Belousov ipsec4_checkpolicy(const struct mbuf *m, struct inpcb *inp, struct ip *ip1, 5960ff2d00dSKonstantin Belousov int *error, int needport) 597fcf59617SAndrey V. Elsukov { 598fcf59617SAndrey V. Elsukov struct secpolicy *sp; 599fcf59617SAndrey V. Elsukov 600fcf59617SAndrey V. Elsukov *error = 0; 6010ff2d00dSKonstantin Belousov sp = ipsec4_getpolicy(m, inp, ip1, IPSEC_DIR_OUTBOUND, needport); 602fcf59617SAndrey V. Elsukov if (sp != NULL) 603fcf59617SAndrey V. Elsukov sp = ipsec_checkpolicy(sp, inp, error); 604fcf59617SAndrey V. Elsukov if (sp == NULL) { 605fcf59617SAndrey V. Elsukov switch (*error) { 606fcf59617SAndrey V. Elsukov case 0: /* No IPsec required: BYPASS or NONE */ 607fcf59617SAndrey V. Elsukov break; 608fcf59617SAndrey V. Elsukov case -EINVAL: 609fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_out_polvio); 610fcf59617SAndrey V. Elsukov break; 611fcf59617SAndrey V. Elsukov default: 612fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_out_inval); 613fcf59617SAndrey V. Elsukov } 614fcf59617SAndrey V. Elsukov } 615fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 616fcf59617SAndrey V. Elsukov printf("%s: using SP(%p), error %d\n", __func__, sp, *error)); 617fcf59617SAndrey V. Elsukov if (sp != NULL) 618fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 619fcf59617SAndrey V. Elsukov return (sp); 620fcf59617SAndrey V. Elsukov } 621fcf59617SAndrey V. Elsukov 622fcf59617SAndrey V. Elsukov /* 623fcf59617SAndrey V. Elsukov * Check IPv4 packet against *INBOUND* security policy. 624fcf59617SAndrey V. Elsukov * This function is called from tcp_input(), udp_input(), 625fcf59617SAndrey V. Elsukov * rip_input() and sctp_input(). 626fcf59617SAndrey V. Elsukov */ 627fcf59617SAndrey V. Elsukov int 6280ff2d00dSKonstantin Belousov ipsec4_in_reject1(const struct mbuf *m, struct ip *ip1, struct inpcb *inp) 629fcf59617SAndrey V. Elsukov { 630fcf59617SAndrey V. Elsukov struct secpolicy *sp; 631ef2a572bSKonstantin Belousov #ifdef IPSEC_OFFLOAD 632ef2a572bSKonstantin Belousov struct ipsec_accel_in_tag *tag; 633ef2a572bSKonstantin Belousov #endif 6340ff2d00dSKonstantin Belousov struct ip ip_hdr; 635fcf59617SAndrey V. Elsukov int result; 636fcf59617SAndrey V. Elsukov 637ef2a572bSKonstantin Belousov #ifdef IPSEC_OFFLOAD 638ef2a572bSKonstantin Belousov tag = ipsec_accel_input_tag_lookup(m); 639ef2a572bSKonstantin Belousov if (tag != NULL) 640ef2a572bSKonstantin Belousov return (0); 641ef2a572bSKonstantin Belousov #endif 6420ff2d00dSKonstantin Belousov 6430ff2d00dSKonstantin Belousov if (ip1 == NULL) { 6440ff2d00dSKonstantin Belousov ip1 = &ip_hdr; 6450ff2d00dSKonstantin Belousov m_copydata(m, 0, sizeof(*ip1), (char *)ip1); 6460ff2d00dSKonstantin Belousov } 6470ff2d00dSKonstantin Belousov 6480ff2d00dSKonstantin Belousov sp = ipsec4_getpolicy(m, inp, ip1, IPSEC_DIR_INBOUND, 0); 649fcf59617SAndrey V. Elsukov result = ipsec_in_reject(sp, inp, m); 650fcf59617SAndrey V. Elsukov key_freesp(&sp); 651fcf59617SAndrey V. Elsukov if (result != 0) 652fcf59617SAndrey V. Elsukov IPSECSTAT_INC(ips_in_polvio); 653fcf59617SAndrey V. Elsukov return (result); 654fcf59617SAndrey V. Elsukov } 655fcf59617SAndrey V. Elsukov 6560ff2d00dSKonstantin Belousov int 6570ff2d00dSKonstantin Belousov ipsec4_in_reject(const struct mbuf *m, struct inpcb *inp) 6580ff2d00dSKonstantin Belousov { 6590ff2d00dSKonstantin Belousov return (ipsec4_in_reject1(m, NULL, inp)); 6600ff2d00dSKonstantin Belousov } 6610ff2d00dSKonstantin Belousov 662fcf59617SAndrey V. Elsukov /* 663fcf59617SAndrey V. Elsukov * IPSEC_CAP() method implementation for IPv4. 664fcf59617SAndrey V. Elsukov */ 665fcf59617SAndrey V. Elsukov int 666fcf59617SAndrey V. Elsukov ipsec4_capability(struct mbuf *m, u_int cap) 667fcf59617SAndrey V. Elsukov { 668fcf59617SAndrey V. Elsukov 669fcf59617SAndrey V. Elsukov switch (cap) { 670fcf59617SAndrey V. Elsukov case IPSEC_CAP_BYPASS_FILTER: 671fcf59617SAndrey V. Elsukov /* 672fcf59617SAndrey V. Elsukov * Bypass packet filtering for packets previously handled 673fcf59617SAndrey V. Elsukov * by IPsec. 674fcf59617SAndrey V. Elsukov */ 675fcf59617SAndrey V. Elsukov if (!V_ip4_filtertunnel && 676fcf59617SAndrey V. Elsukov m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 677fcf59617SAndrey V. Elsukov return (1); 678fcf59617SAndrey V. Elsukov return (0); 679fcf59617SAndrey V. Elsukov case IPSEC_CAP_OPERABLE: 680fcf59617SAndrey V. Elsukov /* Do we have active security policies? */ 681c1bfe8c5SMateusz Guzik return (key_havesp_any()); 682fcf59617SAndrey V. Elsukov }; 683fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 684fcf59617SAndrey V. Elsukov } 685fcf59617SAndrey V. Elsukov 686fcf59617SAndrey V. Elsukov #endif /* INET */ 687fcf59617SAndrey V. Elsukov 68888768458SSam Leffler #ifdef INET6 68988768458SSam Leffler static void 690efb10c3cSAndrey V. Elsukov ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx, 691efb10c3cSAndrey V. Elsukov int needport) 69288768458SSam Leffler { 69388768458SSam Leffler struct tcphdr th; 69488768458SSam Leffler struct udphdr uh; 6950e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 696fcf59617SAndrey V. Elsukov int off, nxt; 69788768458SSam Leffler 698fcf59617SAndrey V. Elsukov IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip6_hdr), 699fcf59617SAndrey V. Elsukov ("packet too short")); 70088768458SSam Leffler 701de47c390SBjoern A. Zeeb /* Set default. */ 70288768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 703fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = IPSEC_PORT_ANY; 704fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = IPSEC_PORT_ANY; 70588768458SSam Leffler 70688768458SSam Leffler nxt = -1; 70788768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 70888768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 70988768458SSam Leffler return; 71088768458SSam Leffler 71188768458SSam Leffler switch (nxt) { 71288768458SSam Leffler case IPPROTO_TCP: 71388768458SSam Leffler spidx->ul_proto = nxt; 71488768458SSam Leffler if (!needport) 71588768458SSam Leffler break; 71688768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 71788768458SSam Leffler break; 71888768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 719fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = th.th_sport; 720fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = th.th_dport; 72188768458SSam Leffler break; 72288768458SSam Leffler case IPPROTO_UDP: 72388768458SSam Leffler spidx->ul_proto = nxt; 72488768458SSam Leffler if (!needport) 72588768458SSam Leffler break; 72688768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 72788768458SSam Leffler break; 72888768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 729fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = uh.uh_sport; 730fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = uh.uh_dport; 73188768458SSam Leffler break; 73288768458SSam Leffler case IPPROTO_ICMPV6: 7330e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 7340e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 7350e3c2be4SBjoern A. Zeeb break; 7360e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 737fcf59617SAndrey V. Elsukov spidx->src.sin6.sin6_port = htons((uint16_t)ih.icmp6_type); 738fcf59617SAndrey V. Elsukov spidx->dst.sin6.sin6_port = htons((uint16_t)ih.icmp6_code); 7390e3c2be4SBjoern A. Zeeb break; 74088768458SSam Leffler default: 741de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 74288768458SSam Leffler spidx->ul_proto = nxt; 74388768458SSam Leffler break; 74488768458SSam Leffler } 745fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 746fcf59617SAndrey V. Elsukov printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL)); 74788768458SSam Leffler } 74888768458SSam Leffler 749fcf59617SAndrey V. Elsukov static void 750efb10c3cSAndrey V. Elsukov ipsec6_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) 75188768458SSam Leffler { 75288768458SSam Leffler 753fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(m, &spidx->src, &spidx->dst); 75488768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 75588768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 75688768458SSam Leffler } 757fcf59617SAndrey V. Elsukov 758fcf59617SAndrey V. Elsukov static struct secpolicy * 75922bbefb2SAndrey V. Elsukov ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir, 76022bbefb2SAndrey V. Elsukov int needport) 761fcf59617SAndrey V. Elsukov { 762fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 763fcf59617SAndrey V. Elsukov struct secpolicy *sp; 764fcf59617SAndrey V. Elsukov 765fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, dir); 766fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(dir)) { 767fcf59617SAndrey V. Elsukov /* Make an index to look for a policy. */ 768fcf59617SAndrey V. Elsukov ipsec6_setspidx_ipaddr(m, &spidx); 76922bbefb2SAndrey V. Elsukov ipsec6_get_ulp(m, &spidx, needport); 770fcf59617SAndrey V. Elsukov spidx.dir = dir; 771fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, dir); 772fcf59617SAndrey V. Elsukov } 773fcf59617SAndrey V. Elsukov if (sp == NULL) /* No SP found, use system default. */ 774fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 775fcf59617SAndrey V. Elsukov return (sp); 776fcf59617SAndrey V. Elsukov } 777fcf59617SAndrey V. Elsukov 778fcf59617SAndrey V. Elsukov /* 779fcf59617SAndrey V. Elsukov * Check security policy for *OUTBOUND* IPv6 packet. 780fcf59617SAndrey V. Elsukov */ 781fcf59617SAndrey V. Elsukov struct secpolicy * 78222bbefb2SAndrey V. Elsukov ipsec6_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error, 78322bbefb2SAndrey V. Elsukov int needport) 784fcf59617SAndrey V. Elsukov { 785fcf59617SAndrey V. Elsukov struct secpolicy *sp; 786fcf59617SAndrey V. Elsukov 787fcf59617SAndrey V. Elsukov *error = 0; 78822bbefb2SAndrey V. Elsukov sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport); 789fcf59617SAndrey V. Elsukov if (sp != NULL) 790fcf59617SAndrey V. Elsukov sp = ipsec_checkpolicy(sp, inp, error); 791fcf59617SAndrey V. Elsukov if (sp == NULL) { 792fcf59617SAndrey V. Elsukov switch (*error) { 793fcf59617SAndrey V. Elsukov case 0: /* No IPsec required: BYPASS or NONE */ 794fcf59617SAndrey V. Elsukov break; 795fcf59617SAndrey V. Elsukov case -EINVAL: 796fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_polvio); 797fcf59617SAndrey V. Elsukov break; 798fcf59617SAndrey V. Elsukov default: 799fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_inval); 800fcf59617SAndrey V. Elsukov } 801fcf59617SAndrey V. Elsukov } 802fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 803fcf59617SAndrey V. Elsukov printf("%s: using SP(%p), error %d\n", __func__, sp, *error)); 804fcf59617SAndrey V. Elsukov if (sp != NULL) 805fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 806fcf59617SAndrey V. Elsukov return (sp); 807fcf59617SAndrey V. Elsukov } 808fcf59617SAndrey V. Elsukov 809fcf59617SAndrey V. Elsukov /* 810fcf59617SAndrey V. Elsukov * Check IPv6 packet against inbound security policy. 811fcf59617SAndrey V. Elsukov * This function is called from tcp6_input(), udp6_input(), 812fcf59617SAndrey V. Elsukov * rip6_input() and sctp_input(). 813fcf59617SAndrey V. Elsukov */ 814fcf59617SAndrey V. Elsukov int 815fcf59617SAndrey V. Elsukov ipsec6_in_reject(const struct mbuf *m, struct inpcb *inp) 816fcf59617SAndrey V. Elsukov { 817fcf59617SAndrey V. Elsukov struct secpolicy *sp; 818ef2a572bSKonstantin Belousov #ifdef IPSEC_OFFLOAD 819ef2a572bSKonstantin Belousov struct ipsec_accel_in_tag *tag; 820ef2a572bSKonstantin Belousov #endif 821fcf59617SAndrey V. Elsukov int result; 822fcf59617SAndrey V. Elsukov 823ef2a572bSKonstantin Belousov #ifdef IPSEC_OFFLOAD 824ef2a572bSKonstantin Belousov tag = ipsec_accel_input_tag_lookup(m); 825ef2a572bSKonstantin Belousov if (tag != NULL) 826ef2a572bSKonstantin Belousov return (0); 827ef2a572bSKonstantin Belousov #endif 82822bbefb2SAndrey V. Elsukov sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0); 829fcf59617SAndrey V. Elsukov result = ipsec_in_reject(sp, inp, m); 830fcf59617SAndrey V. Elsukov key_freesp(&sp); 831fcf59617SAndrey V. Elsukov if (result) 832fcf59617SAndrey V. Elsukov IPSEC6STAT_INC(ips_in_polvio); 833fcf59617SAndrey V. Elsukov return (result); 834fcf59617SAndrey V. Elsukov } 835fcf59617SAndrey V. Elsukov 836fcf59617SAndrey V. Elsukov /* 837fcf59617SAndrey V. Elsukov * IPSEC_CAP() method implementation for IPv6. 838fcf59617SAndrey V. Elsukov */ 839fcf59617SAndrey V. Elsukov int 840fcf59617SAndrey V. Elsukov ipsec6_capability(struct mbuf *m, u_int cap) 841fcf59617SAndrey V. Elsukov { 842fcf59617SAndrey V. Elsukov 843fcf59617SAndrey V. Elsukov switch (cap) { 844fcf59617SAndrey V. Elsukov case IPSEC_CAP_BYPASS_FILTER: 845fcf59617SAndrey V. Elsukov /* 846fcf59617SAndrey V. Elsukov * Bypass packet filtering for packets previously handled 847fcf59617SAndrey V. Elsukov * by IPsec. 848fcf59617SAndrey V. Elsukov */ 849fcf59617SAndrey V. Elsukov if (!V_ip6_filtertunnel && 850fcf59617SAndrey V. Elsukov m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 851fcf59617SAndrey V. Elsukov return (1); 852fcf59617SAndrey V. Elsukov return (0); 853fcf59617SAndrey V. Elsukov case IPSEC_CAP_OPERABLE: 854fcf59617SAndrey V. Elsukov /* Do we have active security policies? */ 855c1bfe8c5SMateusz Guzik return (key_havesp_any()); 856fcf59617SAndrey V. Elsukov }; 857fcf59617SAndrey V. Elsukov return (EOPNOTSUPP); 858fcf59617SAndrey V. Elsukov } 859fcf59617SAndrey V. Elsukov #endif /* INET6 */ 86088768458SSam Leffler 861ef91a976SAndrey V. Elsukov int 862ef91a976SAndrey V. Elsukov ipsec_run_hhooks(struct ipsec_ctx_data *ctx, int type) 863ef91a976SAndrey V. Elsukov { 864ef91a976SAndrey V. Elsukov int idx; 865ef91a976SAndrey V. Elsukov 866ef91a976SAndrey V. Elsukov switch (ctx->af) { 867ef91a976SAndrey V. Elsukov #ifdef INET 868ef91a976SAndrey V. Elsukov case AF_INET: 869ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET; 870ef91a976SAndrey V. Elsukov break; 871ef91a976SAndrey V. Elsukov #endif 872ef91a976SAndrey V. Elsukov #ifdef INET6 873ef91a976SAndrey V. Elsukov case AF_INET6: 874ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET6; 875ef91a976SAndrey V. Elsukov break; 876ef91a976SAndrey V. Elsukov #endif 877ef91a976SAndrey V. Elsukov default: 878ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 879ef91a976SAndrey V. Elsukov } 880ef91a976SAndrey V. Elsukov if (type == HHOOK_TYPE_IPSEC_IN) 881ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_in[idx], ctx, NULL); 882ef91a976SAndrey V. Elsukov else 883ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_out[idx], ctx, NULL); 884ef91a976SAndrey V. Elsukov if (*ctx->mp == NULL) 885ef91a976SAndrey V. Elsukov return (EACCES); 886ef91a976SAndrey V. Elsukov return (0); 887ef91a976SAndrey V. Elsukov } 888ef91a976SAndrey V. Elsukov 88988768458SSam Leffler /* 890de47c390SBjoern A. Zeeb * Return current level. 89188768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 89288768458SSam Leffler */ 89388768458SSam Leffler u_int 894fcf59617SAndrey V. Elsukov ipsec_get_reqlevel(struct secpolicy *sp, u_int idx) 89588768458SSam Leffler { 896fcf59617SAndrey V. Elsukov struct ipsecrequest *isr; 89788768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 89888768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 899fcf59617SAndrey V. Elsukov u_int level = 0; 90088768458SSam Leffler 901fcf59617SAndrey V. Elsukov IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx)); 902de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */ 90388768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 904fcf59617SAndrey V. Elsukov (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE && \ 905fcf59617SAndrey V. Elsukov (lev) != IPSEC_LEVEL_UNIQUE) \ 906fcf59617SAndrey V. Elsukov ? (V_ipsec_debug ? \ 907fcf59617SAndrey V. Elsukov log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 908fcf59617SAndrey V. Elsukov (lev), IPSEC_LEVEL_REQUIRE) : 0), \ 909fcf59617SAndrey V. Elsukov (lev) = IPSEC_LEVEL_REQUIRE, (lev) : (lev)) 910fcf59617SAndrey V. Elsukov 911fcf59617SAndrey V. Elsukov /* 912fcf59617SAndrey V. Elsukov * IPsec VTI uses unique security policy with fake spidx filled 913fcf59617SAndrey V. Elsukov * with zeroes. Just return IPSEC_LEVEL_REQUIRE instead of doing 914fcf59617SAndrey V. Elsukov * full level lookup for such policies. 915fcf59617SAndrey V. Elsukov */ 916fcf59617SAndrey V. Elsukov if (sp->state == IPSEC_SPSTATE_IFNET) { 917fcf59617SAndrey V. Elsukov IPSEC_ASSERT(sp->req[idx]->level == IPSEC_LEVEL_UNIQUE, 918fcf59617SAndrey V. Elsukov ("Wrong IPsec request level %d", sp->req[idx]->level)); 919fcf59617SAndrey V. Elsukov return (IPSEC_LEVEL_REQUIRE); 920fcf59617SAndrey V. Elsukov } 92188768458SSam Leffler 922de47c390SBjoern A. Zeeb /* Set default level. */ 923fcf59617SAndrey V. Elsukov switch (sp->spidx.src.sa.sa_family) { 92488768458SSam Leffler #ifdef INET 92588768458SSam Leffler case AF_INET: 926603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 927603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 928603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 929603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 93088768458SSam Leffler break; 93188768458SSam Leffler #endif 93288768458SSam Leffler #ifdef INET6 93388768458SSam Leffler case AF_INET6: 934603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 935603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 936603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 937603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 93888768458SSam Leffler break; 93988768458SSam Leffler #endif /* INET6 */ 94088768458SSam Leffler default: 9419ffa9677SSam Leffler panic("%s: unknown af %u", 942fcf59617SAndrey V. Elsukov __func__, sp->spidx.src.sa.sa_family); 94388768458SSam Leffler } 94488768458SSam Leffler 94588768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 94688768458SSam Leffler 947fcf59617SAndrey V. Elsukov isr = sp->req[idx]; 948de47c390SBjoern A. Zeeb /* Set level. */ 94988768458SSam Leffler switch (isr->level) { 95088768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 95188768458SSam Leffler switch (isr->saidx.proto) { 95288768458SSam Leffler case IPPROTO_ESP: 95388768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 95488768458SSam Leffler level = esp_net_deflev; 95588768458SSam Leffler else 95688768458SSam Leffler level = esp_trans_deflev; 95788768458SSam Leffler break; 95888768458SSam Leffler case IPPROTO_AH: 95988768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 96088768458SSam Leffler level = ah_net_deflev; 96188768458SSam Leffler else 96288768458SSam Leffler level = ah_trans_deflev; 9638381996eSSam Leffler break; 96488768458SSam Leffler case IPPROTO_IPCOMP: 96588768458SSam Leffler /* 966de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document says that 967de47c390SBjoern A. Zeeb * we shouldn't compress small packets. 96888768458SSam Leffler */ 96988768458SSam Leffler level = IPSEC_LEVEL_USE; 97088768458SSam Leffler break; 97188768458SSam Leffler default: 9729ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 97388768458SSam Leffler isr->saidx.proto); 97488768458SSam Leffler } 97588768458SSam Leffler break; 97688768458SSam Leffler 97788768458SSam Leffler case IPSEC_LEVEL_USE: 97888768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 97988768458SSam Leffler level = isr->level; 98088768458SSam Leffler break; 98188768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 98288768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 98388768458SSam Leffler break; 98488768458SSam Leffler 98588768458SSam Leffler default: 9869ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 98788768458SSam Leffler } 98888768458SSam Leffler 989de47c390SBjoern A. Zeeb return (level); 99088768458SSam Leffler } 99188768458SSam Leffler 992fcf59617SAndrey V. Elsukov static int 993fcf59617SAndrey V. Elsukov ipsec_check_history(const struct mbuf *m, struct secpolicy *sp, u_int idx) 994fcf59617SAndrey V. Elsukov { 995fcf59617SAndrey V. Elsukov struct xform_history *xh; 996fcf59617SAndrey V. Elsukov struct m_tag *mtag; 997fcf59617SAndrey V. Elsukov 998fcf59617SAndrey V. Elsukov mtag = NULL; 999fcf59617SAndrey V. Elsukov while ((mtag = m_tag_find(__DECONST(struct mbuf *, m), 1000fcf59617SAndrey V. Elsukov PACKET_TAG_IPSEC_IN_DONE, mtag)) != NULL) { 1001fcf59617SAndrey V. Elsukov xh = (struct xform_history *)(mtag + 1); 1002fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, 1003fcf59617SAndrey V. Elsukov char buf[IPSEC_ADDRSTRLEN]; 1004fcf59617SAndrey V. Elsukov printf("%s: mode %s proto %u dst %s\n", __func__, 1005fcf59617SAndrey V. Elsukov kdebug_secasindex_mode(xh->mode), xh->proto, 1006fcf59617SAndrey V. Elsukov ipsec_address(&xh->dst, buf, sizeof(buf)))); 1007fcf59617SAndrey V. Elsukov if (xh->proto != sp->req[idx]->saidx.proto) 1008fcf59617SAndrey V. Elsukov continue; 1009fcf59617SAndrey V. Elsukov /* If SA had IPSEC_MODE_ANY, consider this as match. */ 1010fcf59617SAndrey V. Elsukov if (xh->mode != sp->req[idx]->saidx.mode && 1011fcf59617SAndrey V. Elsukov xh->mode != IPSEC_MODE_ANY) 1012fcf59617SAndrey V. Elsukov continue; 1013fcf59617SAndrey V. Elsukov /* 1014fcf59617SAndrey V. Elsukov * For transport mode IPsec request doesn't contain 1015fcf59617SAndrey V. Elsukov * addresses. We need to use address from spidx. 1016fcf59617SAndrey V. Elsukov */ 1017fcf59617SAndrey V. Elsukov if (sp->req[idx]->saidx.mode == IPSEC_MODE_TRANSPORT) { 1018fcf59617SAndrey V. Elsukov if (key_sockaddrcmp_withmask(&xh->dst.sa, 1019fcf59617SAndrey V. Elsukov &sp->spidx.dst.sa, sp->spidx.prefd) != 0) 1020fcf59617SAndrey V. Elsukov continue; 1021fcf59617SAndrey V. Elsukov } else { 1022fcf59617SAndrey V. Elsukov if (key_sockaddrcmp(&xh->dst.sa, 1023fcf59617SAndrey V. Elsukov &sp->req[idx]->saidx.dst.sa, 0) != 0) 1024fcf59617SAndrey V. Elsukov continue; 1025fcf59617SAndrey V. Elsukov } 1026fcf59617SAndrey V. Elsukov return (0); /* matched */ 1027fcf59617SAndrey V. Elsukov } 1028fcf59617SAndrey V. Elsukov return (1); 1029fcf59617SAndrey V. Elsukov } 1030fcf59617SAndrey V. Elsukov 103188768458SSam Leffler /* 103288768458SSam Leffler * Check security policy requirements against the actual 103388768458SSam Leffler * packet contents. Return one if the packet should be 1034424f1296SKonstantin Belousov * rejected as "invalid"; otherwise return zero to have the 103588768458SSam Leffler * packet treated as "valid". 103688768458SSam Leffler * 103788768458SSam Leffler * OUT: 103888768458SSam Leffler * 0: valid 103988768458SSam Leffler * 1: invalid 104088768458SSam Leffler */ 1041a9b9f6b6SAndrey V. Elsukov static int 1042fcf59617SAndrey V. Elsukov ipsec_in_reject(struct secpolicy *sp, struct inpcb *inp, const struct mbuf *m) 104388768458SSam Leffler { 1044fcf59617SAndrey V. Elsukov int i; 104588768458SSam Leffler 1046fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 1047fcf59617SAndrey V. Elsukov printf("%s: PCB(%p): using SP(%p)\n", __func__, inp, sp)); 1048fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 1049fcf59617SAndrey V. Elsukov 1050fcf59617SAndrey V. Elsukov if (inp != NULL && inp->inp_sp != NULL && inp->inp_sp->sp_in == NULL) 1051fcf59617SAndrey V. Elsukov ipsec_cachepolicy(inp, sp, IPSEC_DIR_INBOUND); 105288768458SSam Leffler 1053de47c390SBjoern A. Zeeb /* Check policy. */ 105488768458SSam Leffler switch (sp->policy) { 105588768458SSam Leffler case IPSEC_POLICY_DISCARD: 1056de47c390SBjoern A. Zeeb return (1); 105788768458SSam Leffler case IPSEC_POLICY_BYPASS: 105888768458SSam Leffler case IPSEC_POLICY_NONE: 1059de47c390SBjoern A. Zeeb return (0); 106088768458SSam Leffler } 106188768458SSam Leffler 10629ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 10639ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 106488768458SSam Leffler 1065fcf59617SAndrey V. Elsukov /* 1066fcf59617SAndrey V. Elsukov * ipsec[46]_common_input_cb after each transform adds 1067fcf59617SAndrey V. Elsukov * PACKET_TAG_IPSEC_IN_DONE mbuf tag. It contains SPI, proto, mode 1068fcf59617SAndrey V. Elsukov * and destination address from saidx. We can compare info from 1069fcf59617SAndrey V. Elsukov * these tags with requirements in SP. 1070fcf59617SAndrey V. Elsukov */ 1071fcf59617SAndrey V. Elsukov for (i = 0; i < sp->tcount; i++) { 1072fcf59617SAndrey V. Elsukov /* 1073fcf59617SAndrey V. Elsukov * Do not check IPcomp, since IPcomp document 1074fcf59617SAndrey V. Elsukov * says that we shouldn't compress small packets. 1075fcf59617SAndrey V. Elsukov * IPComp policy should always be treated as being 1076fcf59617SAndrey V. Elsukov * in "use" level. 1077fcf59617SAndrey V. Elsukov */ 1078fcf59617SAndrey V. Elsukov if (sp->req[i]->saidx.proto == IPPROTO_IPCOMP || 1079fcf59617SAndrey V. Elsukov ipsec_get_reqlevel(sp, i) != IPSEC_LEVEL_REQUIRE) 108088768458SSam Leffler continue; 1081fcf59617SAndrey V. Elsukov if (V_check_policy_history != 0 && 1082fcf59617SAndrey V. Elsukov ipsec_check_history(m, sp, i) != 0) 1083fcf59617SAndrey V. Elsukov return (1); 1084fcf59617SAndrey V. Elsukov else switch (sp->req[i]->saidx.proto) { 108588768458SSam Leffler case IPPROTO_ESP: 108688768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 1087fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 10889ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 108988768458SSam Leffler m->m_flags)); 1090de47c390SBjoern A. Zeeb return (1); 109188768458SSam Leffler } 109288768458SSam Leffler break; 109388768458SSam Leffler case IPPROTO_AH: 109488768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 1095fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DUMP, 10969ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 109788768458SSam Leffler m->m_flags)); 1098de47c390SBjoern A. Zeeb return (1); 109988768458SSam Leffler } 110088768458SSam Leffler break; 110188768458SSam Leffler } 110288768458SSam Leffler } 1103de47c390SBjoern A. Zeeb return (0); /* Valid. */ 110488768458SSam Leffler } 110588768458SSam Leffler 1106a91150daSAndrey V. Elsukov /* 1107de47c390SBjoern A. Zeeb * Compute the byte size to be occupied by IPsec header. 1108de47c390SBjoern A. Zeeb * In case it is tunnelled, it includes the size of outer IP header. 110988768458SSam Leffler */ 11106b66194bSKornel Duleba size_t 111197aa4a51SBjoern A. Zeeb ipsec_hdrsiz_internal(struct secpolicy *sp) 111288768458SSam Leffler { 11131f8bd75eSBjoern A. Zeeb size_t size; 1114fcf59617SAndrey V. Elsukov int i; 111588768458SSam Leffler 1116fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, printf("%s: using SP(%p)\n", __func__, sp)); 1117fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secpolicy(sp)); 111888768458SSam Leffler 111988768458SSam Leffler switch (sp->policy) { 112088768458SSam Leffler case IPSEC_POLICY_DISCARD: 112188768458SSam Leffler case IPSEC_POLICY_BYPASS: 112288768458SSam Leffler case IPSEC_POLICY_NONE: 1123de47c390SBjoern A. Zeeb return (0); 112488768458SSam Leffler } 112588768458SSam Leffler 11269ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 11279ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 112888768458SSam Leffler 1129fcf59617SAndrey V. Elsukov /* 1130fcf59617SAndrey V. Elsukov * XXX: for each transform we need to lookup suitable SA 1131fcf59617SAndrey V. Elsukov * and use info from SA to calculate headers size. 1132fcf59617SAndrey V. Elsukov * XXX: for NAT-T we need to cosider UDP header size. 1133fcf59617SAndrey V. Elsukov */ 11341f8bd75eSBjoern A. Zeeb size = 0; 1135fcf59617SAndrey V. Elsukov for (i = 0; i < sp->tcount; i++) { 1136fcf59617SAndrey V. Elsukov switch (sp->req[i]->saidx.proto) { 113788768458SSam Leffler case IPPROTO_ESP: 1138fcf59617SAndrey V. Elsukov size += esp_hdrsiz(NULL); 113988768458SSam Leffler break; 114088768458SSam Leffler case IPPROTO_AH: 1141fcf59617SAndrey V. Elsukov size += ah_hdrsiz(NULL); 114288768458SSam Leffler break; 114388768458SSam Leffler case IPPROTO_IPCOMP: 1144fcf59617SAndrey V. Elsukov size += sizeof(struct ipcomp); 114588768458SSam Leffler break; 114688768458SSam Leffler } 114788768458SSam Leffler 1148fcf59617SAndrey V. Elsukov if (sp->req[i]->saidx.mode == IPSEC_MODE_TUNNEL) { 1149fcf59617SAndrey V. Elsukov switch (sp->req[i]->saidx.dst.sa.sa_family) { 1150fcf59617SAndrey V. Elsukov #ifdef INET 115188768458SSam Leffler case AF_INET: 1152fcf59617SAndrey V. Elsukov size += sizeof(struct ip); 115388768458SSam Leffler break; 1154fcf59617SAndrey V. Elsukov #endif 115588768458SSam Leffler #ifdef INET6 115688768458SSam Leffler case AF_INET6: 1157fcf59617SAndrey V. Elsukov size += sizeof(struct ip6_hdr); 115888768458SSam Leffler break; 115988768458SSam Leffler #endif 116088768458SSam Leffler default: 11619ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 11629ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 1163fcf59617SAndrey V. Elsukov sp->req[i]->saidx.dst.sa.sa_family)); 116488768458SSam Leffler break; 116588768458SSam Leffler } 116688768458SSam Leffler } 116788768458SSam Leffler } 11681f8bd75eSBjoern A. Zeeb return (size); 116988768458SSam Leffler } 117088768458SSam Leffler 117197aa4a51SBjoern A. Zeeb /* 1172fcf59617SAndrey V. Elsukov * Compute ESP/AH header size for protocols with PCB, including 1173fcf59617SAndrey V. Elsukov * outer IP header. Currently only tcp_output() uses it. 117497aa4a51SBjoern A. Zeeb */ 117588768458SSam Leffler size_t 1176fcf59617SAndrey V. Elsukov ipsec_hdrsiz_inpcb(struct inpcb *inp) 117788768458SSam Leffler { 1178fcf59617SAndrey V. Elsukov struct secpolicyindex spidx; 117988768458SSam Leffler struct secpolicy *sp; 1180fcf59617SAndrey V. Elsukov size_t sz; 118188768458SSam Leffler 1182fcf59617SAndrey V. Elsukov sp = ipsec_getpcbpolicy(inp, IPSEC_DIR_OUTBOUND); 1183fcf59617SAndrey V. Elsukov if (sp == NULL && key_havesp(IPSEC_DIR_OUTBOUND)) { 1184fcf59617SAndrey V. Elsukov ipsec_setspidx_inpcb(inp, &spidx, IPSEC_DIR_OUTBOUND); 1185fcf59617SAndrey V. Elsukov sp = key_allocsp(&spidx, IPSEC_DIR_OUTBOUND); 118688768458SSam Leffler } 1187fcf59617SAndrey V. Elsukov if (sp == NULL) 1188fcf59617SAndrey V. Elsukov sp = key_allocsp_default(); 1189fcf59617SAndrey V. Elsukov sz = ipsec_hdrsiz_internal(sp); 1190fcf59617SAndrey V. Elsukov key_freesp(&sp); 1191fcf59617SAndrey V. Elsukov return (sz); 119288768458SSam Leffler } 119388768458SSam Leffler 11948b7f3994SMarcin Wojtas 11958b7f3994SMarcin Wojtas #define IPSEC_BITMAP_INDEX_MASK(w) (w - 1) 11968b7f3994SMarcin Wojtas #define IPSEC_REDUNDANT_BIT_SHIFTS 5 11978b7f3994SMarcin Wojtas #define IPSEC_REDUNDANT_BITS (1 << IPSEC_REDUNDANT_BIT_SHIFTS) 11988b7f3994SMarcin Wojtas #define IPSEC_BITMAP_LOC_MASK (IPSEC_REDUNDANT_BITS - 1) 11998b7f3994SMarcin Wojtas 12008b7f3994SMarcin Wojtas /* 12018b7f3994SMarcin Wojtas * Functions below are responsible for checking and updating bitmap. 12028b7f3994SMarcin Wojtas * These are used to separate ipsec_chkreplay() and ipsec_updatereplay() 12038b7f3994SMarcin Wojtas * from window implementation 12048b7f3994SMarcin Wojtas * 12058b7f3994SMarcin Wojtas * Based on RFC 6479. Blocks are 32 bits unsigned integers 12068b7f3994SMarcin Wojtas */ 12078b7f3994SMarcin Wojtas 12088b7f3994SMarcin Wojtas static inline int 12098b7f3994SMarcin Wojtas check_window(const struct secreplay *replay, uint64_t seq) 12108b7f3994SMarcin Wojtas { 12118b7f3994SMarcin Wojtas int index, bit_location; 12128b7f3994SMarcin Wojtas 12130361f165SKristof Provost SECREPLAY_ASSERT(replay); 12140361f165SKristof Provost 12158b7f3994SMarcin Wojtas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 12168b7f3994SMarcin Wojtas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS) 12178b7f3994SMarcin Wojtas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 12188b7f3994SMarcin Wojtas 12198b7f3994SMarcin Wojtas /* This packet already seen? */ 12208b7f3994SMarcin Wojtas return ((replay->bitmap)[index] & (1 << bit_location)); 12218b7f3994SMarcin Wojtas } 12228b7f3994SMarcin Wojtas 12238b7f3994SMarcin Wojtas static inline void 12248b7f3994SMarcin Wojtas advance_window(const struct secreplay *replay, uint64_t seq) 12258b7f3994SMarcin Wojtas { 12268b7f3994SMarcin Wojtas int i; 12278b7f3994SMarcin Wojtas uint64_t index, index_cur, diff; 12288b7f3994SMarcin Wojtas 12290361f165SKristof Provost SECREPLAY_ASSERT(replay); 12300361f165SKristof Provost 12318b7f3994SMarcin Wojtas index_cur = replay->last >> IPSEC_REDUNDANT_BIT_SHIFTS; 12328b7f3994SMarcin Wojtas index = seq >> IPSEC_REDUNDANT_BIT_SHIFTS; 12338b7f3994SMarcin Wojtas diff = index - index_cur; 12348b7f3994SMarcin Wojtas 12358b7f3994SMarcin Wojtas if (diff > replay->bitmap_size) { 12368b7f3994SMarcin Wojtas /* something unusual in this case */ 12378b7f3994SMarcin Wojtas diff = replay->bitmap_size; 12388b7f3994SMarcin Wojtas } 12398b7f3994SMarcin Wojtas 12408b7f3994SMarcin Wojtas for (i = 0; i < diff; i++) { 12418b7f3994SMarcin Wojtas replay->bitmap[(i + index_cur + 1) 12428b7f3994SMarcin Wojtas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size)] = 0; 12438b7f3994SMarcin Wojtas } 12448b7f3994SMarcin Wojtas } 12458b7f3994SMarcin Wojtas 12468b7f3994SMarcin Wojtas static inline void 12478b7f3994SMarcin Wojtas set_window(const struct secreplay *replay, uint64_t seq) 12488b7f3994SMarcin Wojtas { 12498b7f3994SMarcin Wojtas int index, bit_location; 12508b7f3994SMarcin Wojtas 12510361f165SKristof Provost SECREPLAY_ASSERT(replay); 12520361f165SKristof Provost 12538b7f3994SMarcin Wojtas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 12548b7f3994SMarcin Wojtas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS) 12558b7f3994SMarcin Wojtas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 12568b7f3994SMarcin Wojtas 12578b7f3994SMarcin Wojtas replay->bitmap[index] |= (1 << bit_location); 12588b7f3994SMarcin Wojtas } 12598b7f3994SMarcin Wojtas 126088768458SSam Leffler /* 126188768458SSam Leffler * Check the variable replay window. 126288768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 126388768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 126488768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 126588768458SSam Leffler * beforehand). 126688768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 126788768458SSam Leffler * 12688b7f3994SMarcin Wojtas * Based on RFC 4303 126988768458SSam Leffler */ 1270bf435626SFabien Thomas 127188768458SSam Leffler int 12728b7f3994SMarcin Wojtas ipsec_chkreplay(uint32_t seq, uint32_t *seqhigh, struct secasvar *sav) 127388768458SSam Leffler { 12748b7f3994SMarcin Wojtas char buf[128]; 12758b7f3994SMarcin Wojtas struct secreplay *replay; 12768b7f3994SMarcin Wojtas uint32_t window; 12778b7f3994SMarcin Wojtas uint32_t tl, th, bl; 12788b7f3994SMarcin Wojtas uint32_t seqh; 127988768458SSam Leffler 12809ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 12819ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 128288768458SSam Leffler 128388768458SSam Leffler replay = sav->replay; 128488768458SSam Leffler 1285bf435626SFabien Thomas /* No need to check replay if disabled. */ 12860361f165SKristof Provost if (replay->wsize == 0) { 1287fcf59617SAndrey V. Elsukov return (1); 12880361f165SKristof Provost } 12890361f165SKristof Provost 12900361f165SKristof Provost SECREPLAY_LOCK(replay); 129188768458SSam Leffler 12928b7f3994SMarcin Wojtas /* Zero sequence number is not allowed. */ 12930361f165SKristof Provost if (seq == 0 && replay->last == 0) { 12940361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1295fcf59617SAndrey V. Elsukov return (0); 12960361f165SKristof Provost } 129788768458SSam Leffler 12988b7f3994SMarcin Wojtas window = replay->wsize << 3; /* Size of window */ 12998b7f3994SMarcin Wojtas tl = (uint32_t)replay->last; /* Top of window, lower part */ 13008b7f3994SMarcin Wojtas th = (uint32_t)(replay->last >> 32); /* Top of window, high part */ 13018b7f3994SMarcin Wojtas bl = tl - window + 1; /* Bottom of window, lower part */ 130288768458SSam Leffler 13038b7f3994SMarcin Wojtas /* 13048b7f3994SMarcin Wojtas * We keep the high part intact when: 13058b7f3994SMarcin Wojtas * 1) the seq is within [bl, 0xffffffff] and the whole window is 13068b7f3994SMarcin Wojtas * within one subspace; 13078b7f3994SMarcin Wojtas * 2) the seq is within [0, bl) and window spans two subspaces. 1308bf435626SFabien Thomas */ 13098b7f3994SMarcin Wojtas if ((tl >= window - 1 && seq >= bl) || 13108b7f3994SMarcin Wojtas (tl < window - 1 && seq < bl)) { 13118b7f3994SMarcin Wojtas *seqhigh = th; 13128b7f3994SMarcin Wojtas if (seq <= tl) { 13138b7f3994SMarcin Wojtas /* Sequence number inside window - check against replay */ 13140361f165SKristof Provost if (check_window(replay, seq)) { 13150361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1316fcf59617SAndrey V. Elsukov return (0); 13178b7f3994SMarcin Wojtas } 13180361f165SKristof Provost } 13198b7f3994SMarcin Wojtas 13200361f165SKristof Provost SECREPLAY_UNLOCK(replay); 13218b7f3994SMarcin Wojtas /* Sequence number above top of window or not found in bitmap */ 13228b7f3994SMarcin Wojtas return (1); 13238b7f3994SMarcin Wojtas } 13248b7f3994SMarcin Wojtas 13258b7f3994SMarcin Wojtas /* 13268b7f3994SMarcin Wojtas * If ESN is not enabled and packet with highest sequence number 13278b7f3994SMarcin Wojtas * was received we should report overflow 13288b7f3994SMarcin Wojtas */ 13298b7f3994SMarcin Wojtas if (tl == 0xffffffff && !(sav->flags & SADB_X_SAFLAGS_ESN)) { 13308b7f3994SMarcin Wojtas /* Set overflow flag. */ 13318b7f3994SMarcin Wojtas replay->overflow++; 13328b7f3994SMarcin Wojtas 13338b7f3994SMarcin Wojtas if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { 13348b7f3994SMarcin Wojtas if (sav->sah->saidx.proto == IPPROTO_ESP) 13358b7f3994SMarcin Wojtas ESPSTAT_INC(esps_wrap); 13368b7f3994SMarcin Wojtas else if (sav->sah->saidx.proto == IPPROTO_AH) 13378b7f3994SMarcin Wojtas AHSTAT_INC(ahs_wrap); 13380361f165SKristof Provost SECREPLAY_UNLOCK(replay); 13398b7f3994SMarcin Wojtas return (0); 13408b7f3994SMarcin Wojtas } 13418b7f3994SMarcin Wojtas 13428b7f3994SMarcin Wojtas ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 13438b7f3994SMarcin Wojtas __func__, replay->overflow, 13448b7f3994SMarcin Wojtas ipsec_sa2str(sav, buf, sizeof(buf)))); 13458b7f3994SMarcin Wojtas } 13468b7f3994SMarcin Wojtas 13478b7f3994SMarcin Wojtas /* 13488b7f3994SMarcin Wojtas * Seq is within [bl, 0xffffffff] and bl is within 13498b7f3994SMarcin Wojtas * [0xffffffff-window, 0xffffffff]. This means we got a seq 13508b7f3994SMarcin Wojtas * which is within our replay window, but in the previous 13518b7f3994SMarcin Wojtas * subspace. 13528b7f3994SMarcin Wojtas */ 13538b7f3994SMarcin Wojtas if (tl < window - 1 && seq >= bl) { 13548b7f3994SMarcin Wojtas if (th == 0) 13558b7f3994SMarcin Wojtas return (0); 13568b7f3994SMarcin Wojtas *seqhigh = th - 1; 13578b7f3994SMarcin Wojtas seqh = th - 1; 13580361f165SKristof Provost if (check_window(replay, seq)) { 13590361f165SKristof Provost SECREPLAY_UNLOCK(replay); 13608b7f3994SMarcin Wojtas return (0); 13610361f165SKristof Provost } 13620361f165SKristof Provost SECREPLAY_UNLOCK(replay); 13638b7f3994SMarcin Wojtas return (1); 13648b7f3994SMarcin Wojtas } 13658b7f3994SMarcin Wojtas 13668b7f3994SMarcin Wojtas /* 13678b7f3994SMarcin Wojtas * Seq is within [0, bl) but the whole window is within one subspace. 13688b7f3994SMarcin Wojtas * This means that seq has wrapped and is in next subspace 13698b7f3994SMarcin Wojtas */ 13708b7f3994SMarcin Wojtas *seqhigh = th + 1; 13718b7f3994SMarcin Wojtas seqh = th + 1; 13728b7f3994SMarcin Wojtas 13738b7f3994SMarcin Wojtas /* Don't let high part wrap. */ 13748b7f3994SMarcin Wojtas if (seqh == 0) { 13758b7f3994SMarcin Wojtas /* Set overflow flag. */ 13768b7f3994SMarcin Wojtas replay->overflow++; 13778b7f3994SMarcin Wojtas 13788b7f3994SMarcin Wojtas if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { 13798b7f3994SMarcin Wojtas if (sav->sah->saidx.proto == IPPROTO_ESP) 13808b7f3994SMarcin Wojtas ESPSTAT_INC(esps_wrap); 13818b7f3994SMarcin Wojtas else if (sav->sah->saidx.proto == IPPROTO_AH) 13828b7f3994SMarcin Wojtas AHSTAT_INC(ahs_wrap); 13830361f165SKristof Provost SECREPLAY_UNLOCK(replay); 13848b7f3994SMarcin Wojtas return (0); 13858b7f3994SMarcin Wojtas } 13868b7f3994SMarcin Wojtas 13878b7f3994SMarcin Wojtas ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 13888b7f3994SMarcin Wojtas __func__, replay->overflow, 13898b7f3994SMarcin Wojtas ipsec_sa2str(sav, buf, sizeof(buf)))); 13908b7f3994SMarcin Wojtas } 13918b7f3994SMarcin Wojtas 13920361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1393fcf59617SAndrey V. Elsukov return (1); 139488768458SSam Leffler } 139588768458SSam Leffler 139688768458SSam Leffler /* 1397de47c390SBjoern A. Zeeb * Check replay counter whether to update or not. 139888768458SSam Leffler * OUT: 0: OK 139988768458SSam Leffler * 1: NG 140088768458SSam Leffler */ 140188768458SSam Leffler int 1402fcf59617SAndrey V. Elsukov ipsec_updatereplay(uint32_t seq, struct secasvar *sav) 140388768458SSam Leffler { 140488768458SSam Leffler struct secreplay *replay; 14058b7f3994SMarcin Wojtas uint32_t window; 14068b7f3994SMarcin Wojtas uint32_t tl, th, bl; 14078b7f3994SMarcin Wojtas uint32_t seqh; 140888768458SSam Leffler 14099ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 14109ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 141188768458SSam Leffler 141288768458SSam Leffler replay = sav->replay; 141388768458SSam Leffler 14148b7f3994SMarcin Wojtas /* No need to check replay if disabled. */ 141588768458SSam Leffler if (replay->wsize == 0) 14168b7f3994SMarcin Wojtas return (0); 141788768458SSam Leffler 14180361f165SKristof Provost SECREPLAY_LOCK(replay); 14190361f165SKristof Provost 14208b7f3994SMarcin Wojtas /* Zero sequence number is not allowed. */ 14210361f165SKristof Provost if (seq == 0 && replay->last == 0) { 14220361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1423fcf59617SAndrey V. Elsukov return (1); 14240361f165SKristof Provost } 142588768458SSam Leffler 14268b7f3994SMarcin Wojtas window = replay->wsize << 3; /* Size of window */ 14278b7f3994SMarcin Wojtas tl = (uint32_t)replay->last; /* Top of window, lower part */ 14288b7f3994SMarcin Wojtas th = (uint32_t)(replay->last >> 32); /* Top of window, high part */ 14298b7f3994SMarcin Wojtas bl = tl - window + 1; /* Bottom of window, lower part */ 143088768458SSam Leffler 14318b7f3994SMarcin Wojtas /* 14328b7f3994SMarcin Wojtas * We keep the high part intact when: 14338b7f3994SMarcin Wojtas * 1) the seq is within [bl, 0xffffffff] and the whole window is 14348b7f3994SMarcin Wojtas * within one subspace; 14358b7f3994SMarcin Wojtas * 2) the seq is within [0, bl) and window spans two subspaces. 14368b7f3994SMarcin Wojtas */ 14378b7f3994SMarcin Wojtas if ((tl >= window - 1 && seq >= bl) || 14388b7f3994SMarcin Wojtas (tl < window - 1 && seq < bl)) { 14398b7f3994SMarcin Wojtas seqh = th; 14408b7f3994SMarcin Wojtas if (seq <= tl) { 14418b7f3994SMarcin Wojtas /* Sequence number inside window - check against replay */ 14420361f165SKristof Provost if (check_window(replay, seq)) { 14430361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1444fcf59617SAndrey V. Elsukov return (1); 14450361f165SKristof Provost } 14468b7f3994SMarcin Wojtas set_window(replay, seq); 14478b7f3994SMarcin Wojtas } else { 14488b7f3994SMarcin Wojtas advance_window(replay, ((uint64_t)seqh << 32) | seq); 14498b7f3994SMarcin Wojtas set_window(replay, seq); 14508b7f3994SMarcin Wojtas replay->last = ((uint64_t)seqh << 32) | seq; 1451fcf59617SAndrey V. Elsukov } 145288768458SSam Leffler 14538b7f3994SMarcin Wojtas /* Sequence number above top of window or not found in bitmap */ 1454d5f39c34SFabien Thomas replay->count++; 14550361f165SKristof Provost SECREPLAY_UNLOCK(replay); 1456fcf59617SAndrey V. Elsukov return (0); 145788768458SSam Leffler } 145888768458SSam Leffler 14590361f165SKristof Provost if (!(sav->flags & SADB_X_SAFLAGS_ESN)) { 14600361f165SKristof Provost SECREPLAY_UNLOCK(replay); 14618b7f3994SMarcin Wojtas return (1); 14620361f165SKristof Provost } 14638b7f3994SMarcin Wojtas 14648b7f3994SMarcin Wojtas /* 14658b7f3994SMarcin Wojtas * Seq is within [bl, 0xffffffff] and bl is within 14668b7f3994SMarcin Wojtas * [0xffffffff-window, 0xffffffff]. This means we got a seq 14678b7f3994SMarcin Wojtas * which is within our replay window, but in the previous 14688b7f3994SMarcin Wojtas * subspace. 14698b7f3994SMarcin Wojtas */ 14708b7f3994SMarcin Wojtas if (tl < window - 1 && seq >= bl) { 14710361f165SKristof Provost if (th == 0) { 14720361f165SKristof Provost SECREPLAY_UNLOCK(replay); 14738b7f3994SMarcin Wojtas return (1); 14740361f165SKristof Provost } 14750361f165SKristof Provost if (check_window(replay, seq)) { 14760361f165SKristof Provost SECREPLAY_UNLOCK(replay); 14778b7f3994SMarcin Wojtas return (1); 14780361f165SKristof Provost } 14798b7f3994SMarcin Wojtas 14808b7f3994SMarcin Wojtas set_window(replay, seq); 14818b7f3994SMarcin Wojtas replay->count++; 14820361f165SKristof Provost SECREPLAY_UNLOCK(replay); 14838b7f3994SMarcin Wojtas return (0); 14848b7f3994SMarcin Wojtas } 14858b7f3994SMarcin Wojtas 14868b7f3994SMarcin Wojtas /* 14878b7f3994SMarcin Wojtas * Seq is within [0, bl) but the whole window is within one subspace. 14888b7f3994SMarcin Wojtas * This means that seq has wrapped and is in next subspace 14898b7f3994SMarcin Wojtas */ 14908b7f3994SMarcin Wojtas seqh = th + 1; 14918b7f3994SMarcin Wojtas 14928b7f3994SMarcin Wojtas /* Don't let high part wrap. */ 14930361f165SKristof Provost if (seqh == 0) { 14940361f165SKristof Provost SECREPLAY_UNLOCK(replay); 14958b7f3994SMarcin Wojtas return (1); 14960361f165SKristof Provost } 14978b7f3994SMarcin Wojtas 14988b7f3994SMarcin Wojtas advance_window(replay, ((uint64_t)seqh << 32) | seq); 14998b7f3994SMarcin Wojtas set_window(replay, seq); 15008b7f3994SMarcin Wojtas replay->last = ((uint64_t)seqh << 32) | seq; 15018b7f3994SMarcin Wojtas replay->count++; 15020361f165SKristof Provost 15030361f165SKristof Provost SECREPLAY_UNLOCK(replay); 15048b7f3994SMarcin Wojtas return (0); 15058b7f3994SMarcin Wojtas } 1506fcf59617SAndrey V. Elsukov int 15072e08e39fSConrad Meyer ipsec_updateid(struct secasvar *sav, crypto_session_t *new, 15082e08e39fSConrad Meyer crypto_session_t *old) 1509fcf59617SAndrey V. Elsukov { 15102e08e39fSConrad Meyer crypto_session_t tmp; 151188768458SSam Leffler 1512fcf59617SAndrey V. Elsukov /* 1513fcf59617SAndrey V. Elsukov * tdb_cryptoid is initialized by xform_init(). 1514fcf59617SAndrey V. Elsukov * Then it can be changed only when some crypto error occurred or 1515fcf59617SAndrey V. Elsukov * when SA is deleted. We stored used cryptoid in the xform_data 1516fcf59617SAndrey V. Elsukov * structure. In case when crypto error occurred and crypto 1517fcf59617SAndrey V. Elsukov * subsystem has reinited the session, it returns new cryptoid 1518fcf59617SAndrey V. Elsukov * and EAGAIN error code. 1519fcf59617SAndrey V. Elsukov * 1520fcf59617SAndrey V. Elsukov * This function will be called when we got EAGAIN from crypto 1521fcf59617SAndrey V. Elsukov * subsystem. 1522fcf59617SAndrey V. Elsukov * *new is cryptoid that was returned by crypto subsystem in 1523fcf59617SAndrey V. Elsukov * the crp_sid. 1524fcf59617SAndrey V. Elsukov * *old is the original cryptoid that we stored in xform_data. 1525fcf59617SAndrey V. Elsukov * 1526fcf59617SAndrey V. Elsukov * For first failed request *old == sav->tdb_cryptoid, then 1527fcf59617SAndrey V. Elsukov * we update sav->tdb_cryptoid and redo crypto_dispatch(). 1528fcf59617SAndrey V. Elsukov * For next failed request *old != sav->tdb_cryptoid, then 1529fcf59617SAndrey V. Elsukov * we store cryptoid from first request into the *new variable 1530fcf59617SAndrey V. Elsukov * and crp_sid from this second session will be returned via 1531fcf59617SAndrey V. Elsukov * *old pointer, so caller can release second session. 1532fcf59617SAndrey V. Elsukov * 1533fcf59617SAndrey V. Elsukov * XXXAE: check this more carefully. 1534fcf59617SAndrey V. Elsukov */ 1535fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_STAMP, 15361b0909d5SConrad Meyer printf("%s: SA(%p) moves cryptoid %p -> %p\n", 15371b0909d5SConrad Meyer __func__, sav, *old, *new)); 1538fcf59617SAndrey V. Elsukov KEYDBG(IPSEC_DATA, kdebug_secasv(sav)); 15390361f165SKristof Provost SECASVAR_WLOCK(sav); 1540fcf59617SAndrey V. Elsukov if (sav->tdb_cryptoid != *old) { 1541fcf59617SAndrey V. Elsukov /* cryptoid was already updated */ 1542fcf59617SAndrey V. Elsukov tmp = *new; 1543fcf59617SAndrey V. Elsukov *new = sav->tdb_cryptoid; 1544fcf59617SAndrey V. Elsukov *old = tmp; 15450361f165SKristof Provost SECASVAR_WUNLOCK(sav); 1546fcf59617SAndrey V. Elsukov return (1); 1547fcf59617SAndrey V. Elsukov } 1548fcf59617SAndrey V. Elsukov sav->tdb_cryptoid = *new; 15490361f165SKristof Provost SECASVAR_WUNLOCK(sav); 1550fcf59617SAndrey V. Elsukov return (0); 155188768458SSam Leffler } 155288768458SSam Leffler 1553fcf59617SAndrey V. Elsukov int 1554fcf59617SAndrey V. Elsukov ipsec_initialized(void) 155588768458SSam Leffler { 1556de47c390SBjoern A. Zeeb 1557fcf59617SAndrey V. Elsukov return (V_def_policy != NULL); 155888768458SSam Leffler } 155988768458SSam Leffler 15608381996eSSam Leffler static void 156193201211SAndrey V. Elsukov def_policy_init(const void *unused __unused) 15621ed81b73SMarko Zec { 15631ed81b73SMarko Zec 1564fcf59617SAndrey V. Elsukov V_def_policy = key_newsp(); 1565fcf59617SAndrey V. Elsukov if (V_def_policy != NULL) { 1566fcf59617SAndrey V. Elsukov V_def_policy->policy = IPSEC_POLICY_NONE; 1567fcf59617SAndrey V. Elsukov /* Force INPCB SP cache invalidation */ 1568fcf59617SAndrey V. Elsukov key_bumpspgen(); 1569fcf59617SAndrey V. Elsukov } else 1570fcf59617SAndrey V. Elsukov printf("%s: failed to initialize default policy\n", __func__); 15718381996eSSam Leffler } 1572fcf59617SAndrey V. Elsukov 1573fcf59617SAndrey V. Elsukov static void 1574fcf59617SAndrey V. Elsukov def_policy_uninit(const void *unused __unused) 1575fcf59617SAndrey V. Elsukov { 1576fcf59617SAndrey V. Elsukov 1577fcf59617SAndrey V. Elsukov if (V_def_policy != NULL) { 1578fcf59617SAndrey V. Elsukov key_freesp(&V_def_policy); 1579fcf59617SAndrey V. Elsukov key_bumpspgen(); 1580fcf59617SAndrey V. Elsukov } 1581fcf59617SAndrey V. Elsukov } 1582fcf59617SAndrey V. Elsukov 158389856f7eSBjoern A. Zeeb VNET_SYSINIT(def_policy_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 158493201211SAndrey V. Elsukov def_policy_init, NULL); 1585fcf59617SAndrey V. Elsukov VNET_SYSUNINIT(def_policy_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 1586fcf59617SAndrey V. Elsukov def_policy_uninit, NULL); 1587