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> 9188768458SSam Leffler 9288768458SSam Leffler #include <netipsec/key.h> 9388768458SSam Leffler #include <netipsec/keydb.h> 9488768458SSam Leffler #include <netipsec/key_debug.h> 9588768458SSam Leffler 9688768458SSam Leffler #include <netipsec/xform.h> 9788768458SSam Leffler 9888768458SSam Leffler #include <machine/in_cksum.h> 9988768458SSam Leffler 1007aee3dd1SSam Leffler #include <opencrypto/cryptodev.h> 1017aee3dd1SSam Leffler 102eddfbb76SRobert Watson #ifdef IPSEC_DEBUG 103eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_debug) = 1; 104eddfbb76SRobert Watson #else 105eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_debug) = 0; 106385195c0SMarko Zec #endif 10782cea7e6SBjoern A. Zeeb 108de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */ 109db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec4stat); 110db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec4stat); 111db8c0879SAndrey V. Elsukov 112db8c0879SAndrey V. Elsukov #ifdef VIMAGE 113db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec4stat); 114db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 115db8c0879SAndrey V. Elsukov 116eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_offsetmask) = 0; /* maybe IP_DF? */ 117eddfbb76SRobert Watson /* DF bit on encap. 0: clear 1: set 2: copy */ 118eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_dfbit) = 0; 119eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE; 120eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE; 121eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE; 122eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE; 123eddfbb76SRobert Watson /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 124eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_ecn) = 0; 125eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_randpad) = -1; 126eddfbb76SRobert Watson 12793201211SAndrey V. Elsukov static VNET_DEFINE(struct secpolicy, def_policy); 12893201211SAndrey V. Elsukov #define V_def_policy VNET(def_policy) 12988768458SSam Leffler /* 13088768458SSam Leffler * Crypto support requirements: 13188768458SSam Leffler * 13288768458SSam Leffler * 1 require hardware support 13388768458SSam Leffler * -1 require software support 13488768458SSam Leffler * 0 take anything 13588768458SSam Leffler */ 136eddfbb76SRobert Watson VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 13788768458SSam Leffler 13813a6cf24SBjoern A. Zeeb FEATURE(ipsec, "Internet Protocol Security (IPsec)"); 13913a6cf24SBjoern A. Zeeb #ifdef IPSEC_NAT_T 14013a6cf24SBjoern A. Zeeb FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')"); 14113a6cf24SBjoern A. Zeeb #endif 14213a6cf24SBjoern A. Zeeb 14388768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec); 14488768458SSam Leffler 14588768458SSam Leffler /* net.inet.ipsec */ 1466df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, 14793201211SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(def_policy).policy, 0, 148be6b1304STom Rhodes "IPsec default policy."); 1496df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1506df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0, 1518b615593SMarko Zec "Default ESP transport mode level"); 1526df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1536df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0, 1548b615593SMarko Zec "Default ESP tunnel mode level."); 1556df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1566df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0, 1578b615593SMarko Zec "AH transfer mode default level."); 1586df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 1596df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0, 1608b615593SMarko Zec "AH tunnel mode default level."); 1616df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, 1626df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, 1633377c961STom Rhodes "If set clear type-of-service field when doing AH computation."); 1646df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask, 1656df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_offsetmask), 0, 1663377c961STom Rhodes "If not set clear offset field mask when doing AH computation."); 1676df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit, 1686df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0, 1698b615593SMarko Zec "Do not fragment bit on encap."); 1706df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, 1716df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0, 172be6b1304STom Rhodes "Explicit Congestion Notification handling."); 1736df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, 1746df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_debug), 0, 175be6b1304STom Rhodes "Enable IPsec debugging output when set."); 1766df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support, 1776df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0, 178be6b1304STom Rhodes "Crypto driver selection."); 179db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat, 180db8c0879SAndrey V. Elsukov ipsec4stat, "IPsec IPv4 statistics."); 18188768458SSam Leffler 1826131838bSPawel Jakub Dawidek #ifdef REGRESSION 183dfa9422bSPawel Jakub Dawidek /* 184dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 185dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 186dfa9422bSPawel Jakub Dawidek */ 187eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_replay) = 0; 1886df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, 1896df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0, 190eddfbb76SRobert Watson "Emulate replay attack"); 191dfa9422bSPawel Jakub Dawidek /* 192dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 193dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 194dfa9422bSPawel Jakub Dawidek */ 195eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_integrity) = 0; 1966df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, 1976df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0, 198eddfbb76SRobert Watson "Emulate man-in-the-middle attack"); 1996131838bSPawel Jakub Dawidek #endif 200dfa9422bSPawel Jakub Dawidek 20188768458SSam Leffler #ifdef INET6 202db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec6stat); 203db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec6stat); 204db8c0879SAndrey V. Elsukov 205db8c0879SAndrey V. Elsukov #ifdef VIMAGE 206db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec6stat); 207db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 208db8c0879SAndrey V. Elsukov 209eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE; 210eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE; 211eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE; 212eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE; 213eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ipsec_ecn) = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 21488768458SSam Leffler 21588768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6); 21688768458SSam Leffler 21788768458SSam Leffler /* net.inet6.ipsec6 */ 2186df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, 21993201211SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(def_policy).policy, 0, 2208b615593SMarko Zec "IPsec default policy."); 2216df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 2226df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0, 2238b615593SMarko Zec "Default ESP transport mode level."); 2246df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 2256df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0, 2268b615593SMarko Zec "Default ESP tunnel mode level."); 2276df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 2286df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0, 2298b615593SMarko Zec "AH transfer mode default level."); 2306df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 2316df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0, 2328b615593SMarko Zec "AH tunnel mode default level."); 2336df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, 2346df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0, 2353377c961STom Rhodes "Explicit Congestion Notification handling."); 2366df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, 2376df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_debug), 0, 238be6b1304STom Rhodes "Enable IPsec debugging output when set."); 239db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats, 240db8c0879SAndrey V. Elsukov struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics."); 24188768458SSam Leffler #endif /* INET6 */ 24288768458SSam Leffler 243efb10c3cSAndrey V. Elsukov static int ipsec_in_reject(struct secpolicy *, const struct mbuf *); 244efb10c3cSAndrey V. Elsukov static int ipsec_setspidx_inpcb(const struct mbuf *, struct inpcb *); 245efb10c3cSAndrey V. Elsukov static int ipsec_setspidx(const struct mbuf *, struct secpolicyindex *, int); 246efb10c3cSAndrey V. Elsukov static void ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); 247efb10c3cSAndrey V. Elsukov static int ipsec4_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); 24888768458SSam Leffler #ifdef INET6 249efb10c3cSAndrey V. Elsukov static void ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *, int); 250efb10c3cSAndrey V. Elsukov static int ipsec6_setspidx_ipaddr(const struct mbuf *, struct secpolicyindex *); 25188768458SSam Leffler #endif 25218961126SAndrey V. Elsukov static void ipsec_delpcbpolicy(struct inpcbpolicy *); 25318961126SAndrey V. Elsukov static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src); 25488768458SSam Leffler 2556464079fSSam Leffler MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); 2566464079fSSam Leffler 25788768458SSam Leffler /* 25888768458SSam Leffler * Return a held reference to the default SP. 25988768458SSam Leffler */ 26088768458SSam Leffler static struct secpolicy * 26188768458SSam Leffler key_allocsp_default(const char* where, int tag) 26288768458SSam Leffler { 26388768458SSam Leffler struct secpolicy *sp; 26488768458SSam Leffler 26588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 26688768458SSam Leffler printf("DP key_allocsp_default from %s:%u\n", where, tag)); 26788768458SSam Leffler 26893201211SAndrey V. Elsukov sp = &V_def_policy; 26988768458SSam Leffler if (sp->policy != IPSEC_POLICY_DISCARD && 27088768458SSam Leffler sp->policy != IPSEC_POLICY_NONE) { 27188768458SSam Leffler ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", 27288768458SSam Leffler sp->policy, IPSEC_POLICY_NONE)); 27388768458SSam Leffler sp->policy = IPSEC_POLICY_NONE; 27488768458SSam Leffler } 275422e4f5bSSam Leffler key_addref(sp); 27688768458SSam Leffler 27788768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 27888768458SSam Leffler printf("DP key_allocsp_default returns SP:%p (%u)\n", 27988768458SSam Leffler sp, sp->refcnt)); 280de47c390SBjoern A. Zeeb return (sp); 28188768458SSam Leffler } 28288768458SSam Leffler #define KEY_ALLOCSP_DEFAULT() \ 28388768458SSam Leffler key_allocsp_default(__FILE__, __LINE__) 28488768458SSam Leffler 28588768458SSam Leffler /* 28688768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 28788768458SSam Leffler * and return a pointer to SP. 28888768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 28988768458SSam Leffler * 0 : bypass 29088768458SSam Leffler * EACCES : discard packet. 29188768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 292a4641f4eSPedro F. Giffuni * others : error occurred. 29388768458SSam Leffler * others: a pointer to SP 29488768458SSam Leffler * 29588768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 29688768458SSam Leffler */ 29788768458SSam Leffler struct secpolicy * 29888768458SSam Leffler ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) 29988768458SSam Leffler { 30088768458SSam Leffler struct secpolicy *sp; 30188768458SSam Leffler 3029ffa9677SSam Leffler IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); 3039ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3049ffa9677SSam Leffler ("invalid direction %u", dir)); 30588768458SSam Leffler 30688768458SSam Leffler sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); 30788768458SSam Leffler if (sp == NULL) /*XXX????*/ 30888768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 3099ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 310de47c390SBjoern A. Zeeb return (sp); 31188768458SSam Leffler } 31288768458SSam Leffler 31388768458SSam Leffler /* 31488768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 31588768458SSam Leffler * and return a pointer to SP. 31688768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 31788768458SSam Leffler * 0 : bypass 31888768458SSam Leffler * EACCES : discard packet. 31988768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 320a4641f4eSPedro F. Giffuni * others : error occurred. 32188768458SSam Leffler * others: a pointer to SP 32288768458SSam Leffler * 32388768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 32488768458SSam Leffler */ 325511080aeSBjoern A. Zeeb static struct secpolicy * 326efb10c3cSAndrey V. Elsukov ipsec_getpolicybysock(const struct mbuf *m, u_int dir, struct inpcb *inp, 327efb10c3cSAndrey V. Elsukov int *error) 32888768458SSam Leffler { 32997aa4a51SBjoern A. Zeeb struct inpcbpolicy *pcbsp; 330de47c390SBjoern A. Zeeb struct secpolicy *currsp = NULL; /* Policy on socket. */ 33188768458SSam Leffler struct secpolicy *sp; 33288768458SSam Leffler 3339ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 3349ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inpcb")); 3359ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 3369ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3379ffa9677SSam Leffler ("invalid direction %u", dir)); 33888768458SSam Leffler 339c1fc5e96SErmal Luçi if (!key_havesp(dir)) { 340c1fc5e96SErmal Luçi /* No SP found, use system default. */ 341c1fc5e96SErmal Luçi sp = KEY_ALLOCSP_DEFAULT(); 342c1fc5e96SErmal Luçi return (sp); 343c1fc5e96SErmal Luçi } 344c1fc5e96SErmal Luçi 345de47c390SBjoern A. Zeeb /* Set spidx in pcb. */ 34697aa4a51SBjoern A. Zeeb *error = ipsec_setspidx_inpcb(m, inp); 34788768458SSam Leffler if (*error) 348de47c390SBjoern A. Zeeb return (NULL); 34988768458SSam Leffler 35097aa4a51SBjoern A. Zeeb pcbsp = inp->inp_sp; 3519ffa9677SSam Leffler IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); 35288768458SSam Leffler switch (dir) { 35388768458SSam Leffler case IPSEC_DIR_INBOUND: 35488768458SSam Leffler currsp = pcbsp->sp_in; 35588768458SSam Leffler break; 35688768458SSam Leffler case IPSEC_DIR_OUTBOUND: 35788768458SSam Leffler currsp = pcbsp->sp_out; 35888768458SSam Leffler break; 35988768458SSam Leffler } 3609ffa9677SSam Leffler IPSEC_ASSERT(currsp != NULL, ("null currsp")); 36188768458SSam Leffler 362de47c390SBjoern A. Zeeb if (pcbsp->priv) { /* When privilieged socket. */ 36388768458SSam Leffler switch (currsp->policy) { 36488768458SSam Leffler case IPSEC_POLICY_BYPASS: 36588768458SSam Leffler case IPSEC_POLICY_IPSEC: 366422e4f5bSSam Leffler key_addref(currsp); 36788768458SSam Leffler sp = currsp; 36888768458SSam Leffler break; 36988768458SSam Leffler 37088768458SSam Leffler case IPSEC_POLICY_ENTRUST: 371de47c390SBjoern A. Zeeb /* Look for a policy in SPD. */ 37288768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 373de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found. */ 37488768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 37588768458SSam Leffler break; 37688768458SSam Leffler 37788768458SSam Leffler default: 3789ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", 3799ffa9677SSam Leffler __func__, currsp->policy)); 38088768458SSam Leffler *error = EINVAL; 381de47c390SBjoern A. Zeeb return (NULL); 38288768458SSam Leffler } 383de47c390SBjoern A. Zeeb } else { /* Unpriv, SPD has policy. */ 38488768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 385de47c390SBjoern A. Zeeb if (sp == NULL) { /* No SP found. */ 38688768458SSam Leffler switch (currsp->policy) { 38788768458SSam Leffler case IPSEC_POLICY_BYPASS: 3889ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Illegal policy for " 3899ffa9677SSam Leffler "non-priviliged defined %d\n", 3909ffa9677SSam Leffler __func__, currsp->policy)); 39188768458SSam Leffler *error = EINVAL; 392de47c390SBjoern A. Zeeb return (NULL); 39388768458SSam Leffler 39488768458SSam Leffler case IPSEC_POLICY_ENTRUST: 39588768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 39688768458SSam Leffler break; 39788768458SSam Leffler 39888768458SSam Leffler case IPSEC_POLICY_IPSEC: 399422e4f5bSSam Leffler key_addref(currsp); 40088768458SSam Leffler sp = currsp; 40188768458SSam Leffler break; 40288768458SSam Leffler 40388768458SSam Leffler default: 4049ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for " 4059ffa9677SSam Leffler "PCB %d\n", __func__, currsp->policy)); 40688768458SSam Leffler *error = EINVAL; 407de47c390SBjoern A. Zeeb return (NULL); 40888768458SSam Leffler } 40988768458SSam Leffler } 41088768458SSam Leffler } 4119ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, 4129ffa9677SSam Leffler ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); 41388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 4149ffa9677SSam Leffler printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", 4159ffa9677SSam Leffler __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); 416de47c390SBjoern A. Zeeb return (sp); 41788768458SSam Leffler } 41888768458SSam Leffler 41988768458SSam Leffler /* 42088768458SSam Leffler * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, 42188768458SSam Leffler * and return a pointer to SP. 42288768458SSam Leffler * OUT: positive: a pointer to the entry for security policy leaf matched. 42388768458SSam Leffler * NULL: no apropreate SP found, the following value is set to error. 42488768458SSam Leffler * 0 : bypass 42588768458SSam Leffler * EACCES : discard packet. 42688768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 427a4641f4eSPedro F. Giffuni * others : error occurred. 42888768458SSam Leffler */ 42988768458SSam Leffler struct secpolicy * 430efb10c3cSAndrey V. Elsukov ipsec_getpolicybyaddr(const struct mbuf *m, u_int dir, int *error) 43188768458SSam Leffler { 43288768458SSam Leffler struct secpolicyindex spidx; 43388768458SSam Leffler struct secpolicy *sp; 43488768458SSam Leffler 4359ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 4369ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 4379ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 4389ffa9677SSam Leffler ("invalid direction %u", dir)); 43988768458SSam Leffler 44088768458SSam Leffler sp = NULL; 441e65ada3eSAndrey V. Elsukov *error = 0; 44288768458SSam Leffler if (key_havesp(dir)) { 4439d5abbddSJens Schweikhardt /* Make an index to look for a policy. */ 4440275b2e3SAndrey V. Elsukov *error = ipsec_setspidx(m, &spidx, 0); 44588768458SSam Leffler if (*error != 0) { 4460275b2e3SAndrey V. Elsukov DPRINTF(("%s: setpidx failed, dir %u\n", 4470275b2e3SAndrey V. Elsukov __func__, dir)); 448de47c390SBjoern A. Zeeb return (NULL); 44988768458SSam Leffler } 45088768458SSam Leffler spidx.dir = dir; 45188768458SSam Leffler sp = KEY_ALLOCSP(&spidx, dir); 45288768458SSam Leffler } 453de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found, use system default. */ 45488768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 4559ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 456de47c390SBjoern A. Zeeb return (sp); 45788768458SSam Leffler } 45888768458SSam Leffler 45988768458SSam Leffler struct secpolicy * 460efb10c3cSAndrey V. Elsukov ipsec4_checkpolicy(const struct mbuf *m, u_int dir, int *error, 461efb10c3cSAndrey V. Elsukov struct inpcb *inp) 46288768458SSam Leffler { 46388768458SSam Leffler struct secpolicy *sp; 46488768458SSam Leffler 46588768458SSam Leffler *error = 0; 46688768458SSam Leffler if (inp == NULL) 4670275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, dir, error); 46888768458SSam Leffler else 46988768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, error); 47088768458SSam Leffler if (sp == NULL) { 4719ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); 4726659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_inval); 473de47c390SBjoern A. Zeeb return (NULL); 47488768458SSam Leffler } 4759ffa9677SSam Leffler IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); 47688768458SSam Leffler switch (sp->policy) { 47788768458SSam Leffler case IPSEC_POLICY_ENTRUST: 47888768458SSam Leffler default: 4799ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 480de47c390SBjoern A. Zeeb /* FALLTHROUGH */ 48188768458SSam Leffler case IPSEC_POLICY_DISCARD: 4826659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_polvio); 483de47c390SBjoern A. Zeeb *error = -EINVAL; /* Packet is discarded by caller. */ 48488768458SSam Leffler break; 48588768458SSam Leffler case IPSEC_POLICY_BYPASS: 48688768458SSam Leffler case IPSEC_POLICY_NONE: 48788768458SSam Leffler KEY_FREESP(&sp); 488de47c390SBjoern A. Zeeb sp = NULL; /* NB: force NULL result. */ 48988768458SSam Leffler break; 49088768458SSam Leffler case IPSEC_POLICY_IPSEC: 491de47c390SBjoern A. Zeeb if (sp->req == NULL) /* Acquire a SA. */ 49288768458SSam Leffler *error = key_spdacquire(sp); 49388768458SSam Leffler break; 49488768458SSam Leffler } 49588768458SSam Leffler if (*error != 0) { 49688768458SSam Leffler KEY_FREESP(&sp); 49788768458SSam Leffler sp = NULL; 49888768458SSam Leffler } 499de47c390SBjoern A. Zeeb return (sp); 50088768458SSam Leffler } 50188768458SSam Leffler 50288768458SSam Leffler static int 503efb10c3cSAndrey V. Elsukov ipsec_setspidx_inpcb(const struct mbuf *m, struct inpcb *inp) 50488768458SSam Leffler { 50588768458SSam Leffler int error; 50688768458SSam Leffler 5071f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp != NULL, ("null inp")); 5081f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 5091f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp->inp_sp->sp_out != NULL && inp->inp_sp->sp_in != NULL, 5109ffa9677SSam Leffler ("null sp_in || sp_out")); 51188768458SSam Leffler 5121f8bd75eSBjoern A. Zeeb error = ipsec_setspidx(m, &inp->inp_sp->sp_in->spidx, 1); 51388768458SSam Leffler if (error == 0) { 5141f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 5151f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_out->spidx = inp->inp_sp->sp_in->spidx; 5161f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 51788768458SSam Leffler } else { 5181f8bd75eSBjoern A. Zeeb bzero(&inp->inp_sp->sp_in->spidx, 5191f8bd75eSBjoern A. Zeeb sizeof (inp->inp_sp->sp_in->spidx)); 5201f8bd75eSBjoern A. Zeeb bzero(&inp->inp_sp->sp_out->spidx, 5211f8bd75eSBjoern A. Zeeb sizeof (inp->inp_sp->sp_in->spidx)); 52288768458SSam Leffler } 523de47c390SBjoern A. Zeeb return (error); 52488768458SSam Leffler } 52588768458SSam Leffler 52688768458SSam Leffler /* 527de47c390SBjoern A. Zeeb * Configure security policy index (src/dst/proto/sport/dport) 52888768458SSam Leffler * by looking at the content of mbuf. 529de47c390SBjoern A. Zeeb * The caller is responsible for error recovery (like clearing up spidx). 53088768458SSam Leffler */ 53188768458SSam Leffler static int 532efb10c3cSAndrey V. Elsukov ipsec_setspidx(const struct mbuf *m, struct secpolicyindex *spidx, 533efb10c3cSAndrey V. Elsukov int needport) 53488768458SSam Leffler { 53588768458SSam Leffler struct ip ipbuf; 536efb10c3cSAndrey V. Elsukov const struct ip *ip = NULL; 537efb10c3cSAndrey V. Elsukov const struct mbuf *n; 53888768458SSam Leffler u_int v; 53988768458SSam Leffler int len; 54088768458SSam Leffler int error; 54188768458SSam Leffler 5429ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 54388768458SSam Leffler 54488768458SSam Leffler /* 545de47c390SBjoern A. Zeeb * Validate m->m_pkthdr.len. We see incorrect length if we 54688768458SSam Leffler * mistakenly call this function with inconsistent mbuf chain 547de47c390SBjoern A. Zeeb * (like 4.4BSD tcp/udp processing). XXX Should we panic here? 54888768458SSam Leffler */ 54988768458SSam Leffler len = 0; 55088768458SSam Leffler for (n = m; n; n = n->m_next) 55188768458SSam Leffler len += n->m_len; 55288768458SSam Leffler if (m->m_pkthdr.len != len) { 55388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5549ffa9677SSam Leffler printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", 5559ffa9677SSam Leffler __func__, len, m->m_pkthdr.len)); 556de47c390SBjoern A. Zeeb return (EINVAL); 55788768458SSam Leffler } 55888768458SSam Leffler 55988768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip)) { 56088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5619ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v4), ignored.\n", 5629ffa9677SSam Leffler __func__, m->m_pkthdr.len)); 563de47c390SBjoern A. Zeeb return (EINVAL); 56488768458SSam Leffler } 56588768458SSam Leffler 56688768458SSam Leffler if (m->m_len >= sizeof(*ip)) 567efb10c3cSAndrey V. Elsukov ip = mtod(m, const struct ip *); 56888768458SSam Leffler else { 56988768458SSam Leffler m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); 57088768458SSam Leffler ip = &ipbuf; 57188768458SSam Leffler } 57288768458SSam Leffler v = ip->ip_v; 57388768458SSam Leffler switch (v) { 57488768458SSam Leffler case 4: 57588768458SSam Leffler error = ipsec4_setspidx_ipaddr(m, spidx); 57688768458SSam Leffler if (error) 577de47c390SBjoern A. Zeeb return (error); 57888768458SSam Leffler ipsec4_get_ulp(m, spidx, needport); 579de47c390SBjoern A. Zeeb return (0); 58088768458SSam Leffler #ifdef INET6 58188768458SSam Leffler case 6: 58288768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { 58388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5849ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v6), " 5859ffa9677SSam Leffler "ignored\n", __func__, m->m_pkthdr.len)); 586de47c390SBjoern A. Zeeb return (EINVAL); 58788768458SSam Leffler } 58888768458SSam Leffler error = ipsec6_setspidx_ipaddr(m, spidx); 58988768458SSam Leffler if (error) 590de47c390SBjoern A. Zeeb return (error); 59188768458SSam Leffler ipsec6_get_ulp(m, spidx, needport); 592de47c390SBjoern A. Zeeb return (0); 59388768458SSam Leffler #endif 59488768458SSam Leffler default: 59588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5969ffa9677SSam Leffler printf("%s: " "unknown IP version %u, ignored.\n", 5979ffa9677SSam Leffler __func__, v)); 598de47c390SBjoern A. Zeeb return (EINVAL); 59988768458SSam Leffler } 60088768458SSam Leffler } 60188768458SSam Leffler 60288768458SSam Leffler static void 603efb10c3cSAndrey V. Elsukov ipsec4_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx, 604efb10c3cSAndrey V. Elsukov int needport) 60588768458SSam Leffler { 60688768458SSam Leffler u_int8_t nxt; 60788768458SSam Leffler int off; 60888768458SSam Leffler 609de47c390SBjoern A. Zeeb /* Sanity check. */ 6109ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 6119ffa9677SSam Leffler IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); 61288768458SSam Leffler 61387a25418SErmal Luçi if (m->m_len >= sizeof (struct ip)) { 614efb10c3cSAndrey V. Elsukov const struct ip *ip = mtod(m, const struct ip *); 6158f134647SGleb Smirnoff if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) 61688768458SSam Leffler goto done; 61788768458SSam Leffler off = ip->ip_hl << 2; 61888768458SSam Leffler nxt = ip->ip_p; 61988768458SSam Leffler } else { 62088768458SSam Leffler struct ip ih; 62188768458SSam Leffler 62288768458SSam Leffler m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 6238f134647SGleb Smirnoff if (ih.ip_off & htons(IP_MF | IP_OFFMASK)) 62488768458SSam Leffler goto done; 62588768458SSam Leffler off = ih.ip_hl << 2; 62688768458SSam Leffler nxt = ih.ip_p; 62788768458SSam Leffler } 62888768458SSam Leffler 62988768458SSam Leffler while (off < m->m_pkthdr.len) { 63088768458SSam Leffler struct ip6_ext ip6e; 63188768458SSam Leffler struct tcphdr th; 63288768458SSam Leffler struct udphdr uh; 63388768458SSam Leffler 63488768458SSam Leffler switch (nxt) { 63588768458SSam Leffler case IPPROTO_TCP: 63688768458SSam Leffler spidx->ul_proto = nxt; 63788768458SSam Leffler if (!needport) 63888768458SSam Leffler goto done_proto; 63988768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 64088768458SSam Leffler goto done; 64188768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 64288768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 64388768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 64488768458SSam Leffler return; 64588768458SSam Leffler case IPPROTO_UDP: 64688768458SSam Leffler spidx->ul_proto = nxt; 64788768458SSam Leffler if (!needport) 64888768458SSam Leffler goto done_proto; 64988768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 65088768458SSam Leffler goto done; 65188768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 65288768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 65388768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 65488768458SSam Leffler return; 65588768458SSam Leffler case IPPROTO_AH: 656afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 65788768458SSam Leffler goto done; 658de47c390SBjoern A. Zeeb /* XXX Sigh, this works but is totally bogus. */ 65988768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 66088768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 66188768458SSam Leffler nxt = ip6e.ip6e_nxt; 66288768458SSam Leffler break; 66388768458SSam Leffler case IPPROTO_ICMP: 66488768458SSam Leffler default: 665de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 66688768458SSam Leffler spidx->ul_proto = nxt; 66788768458SSam Leffler goto done_proto; 66888768458SSam Leffler } 66988768458SSam Leffler } 67088768458SSam Leffler done: 67188768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 67288768458SSam Leffler done_proto: 67388768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 67488768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 67588768458SSam Leffler } 67688768458SSam Leffler 677de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 67888768458SSam Leffler static int 679efb10c3cSAndrey V. Elsukov ipsec4_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) 68088768458SSam Leffler { 68188768458SSam Leffler static const struct sockaddr_in template = { 68288768458SSam Leffler sizeof (struct sockaddr_in), 68388768458SSam Leffler AF_INET, 68488768458SSam Leffler 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 68588768458SSam Leffler }; 68688768458SSam Leffler 68788768458SSam Leffler spidx->src.sin = template; 68888768458SSam Leffler spidx->dst.sin = template; 68988768458SSam Leffler 69088768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 69188768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_src), 69288768458SSam Leffler sizeof (struct in_addr), 69388768458SSam Leffler (caddr_t) &spidx->src.sin.sin_addr); 69488768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_dst), 69588768458SSam Leffler sizeof (struct in_addr), 69688768458SSam Leffler (caddr_t) &spidx->dst.sin.sin_addr); 69788768458SSam Leffler } else { 698efb10c3cSAndrey V. Elsukov const struct ip *ip = mtod(m, const struct ip *); 69988768458SSam Leffler spidx->src.sin.sin_addr = ip->ip_src; 70088768458SSam Leffler spidx->dst.sin.sin_addr = ip->ip_dst; 70188768458SSam Leffler } 70288768458SSam Leffler 70388768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 70488768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 70588768458SSam Leffler 706de47c390SBjoern A. Zeeb return (0); 70788768458SSam Leffler } 70888768458SSam Leffler 70988768458SSam Leffler #ifdef INET6 71088768458SSam Leffler static void 711efb10c3cSAndrey V. Elsukov ipsec6_get_ulp(const struct mbuf *m, struct secpolicyindex *spidx, 712efb10c3cSAndrey V. Elsukov int needport) 71388768458SSam Leffler { 71488768458SSam Leffler int off, nxt; 71588768458SSam Leffler struct tcphdr th; 71688768458SSam Leffler struct udphdr uh; 7170e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 71888768458SSam Leffler 719de47c390SBjoern A. Zeeb /* Sanity check. */ 72088768458SSam Leffler if (m == NULL) 7219ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 72288768458SSam Leffler 72388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 7249ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(m)); 72588768458SSam Leffler 726de47c390SBjoern A. Zeeb /* Set default. */ 72788768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 72888768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; 72988768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; 73088768458SSam Leffler 73188768458SSam Leffler nxt = -1; 73288768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 73388768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 73488768458SSam Leffler return; 73588768458SSam Leffler 73688768458SSam Leffler switch (nxt) { 73788768458SSam Leffler case IPPROTO_TCP: 73888768458SSam Leffler spidx->ul_proto = nxt; 73988768458SSam Leffler if (!needport) 74088768458SSam Leffler break; 74188768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 74288768458SSam Leffler break; 74388768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 74488768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; 74588768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; 74688768458SSam Leffler break; 74788768458SSam Leffler case IPPROTO_UDP: 74888768458SSam Leffler spidx->ul_proto = nxt; 74988768458SSam Leffler if (!needport) 75088768458SSam Leffler break; 75188768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 75288768458SSam Leffler break; 75388768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 75488768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; 75588768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; 75688768458SSam Leffler break; 75788768458SSam Leffler case IPPROTO_ICMPV6: 7580e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 7590e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 7600e3c2be4SBjoern A. Zeeb break; 7610e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 7620e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->src)->sin6_port = 7630e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_type); 7640e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = 7650e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_code); 7660e3c2be4SBjoern A. Zeeb break; 76788768458SSam Leffler default: 768de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 76988768458SSam Leffler spidx->ul_proto = nxt; 77088768458SSam Leffler break; 77188768458SSam Leffler } 77288768458SSam Leffler } 77388768458SSam Leffler 774de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 77588768458SSam Leffler static int 776efb10c3cSAndrey V. Elsukov ipsec6_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) 77788768458SSam Leffler { 77888768458SSam Leffler struct ip6_hdr ip6buf; 779efb10c3cSAndrey V. Elsukov const struct ip6_hdr *ip6 = NULL; 78088768458SSam Leffler struct sockaddr_in6 *sin6; 78188768458SSam Leffler 78288768458SSam Leffler if (m->m_len >= sizeof(*ip6)) 783efb10c3cSAndrey V. Elsukov ip6 = mtod(m, const struct ip6_hdr *); 78488768458SSam Leffler else { 78588768458SSam Leffler m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 78688768458SSam Leffler ip6 = &ip6buf; 78788768458SSam Leffler } 78888768458SSam Leffler 78988768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->src; 79088768458SSam Leffler bzero(sin6, sizeof(*sin6)); 79188768458SSam Leffler sin6->sin6_family = AF_INET6; 79288768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 79388768458SSam Leffler bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); 79488768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 79588768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 79688768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); 79788768458SSam Leffler } 79888768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 79988768458SSam Leffler 80088768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->dst; 80188768458SSam Leffler bzero(sin6, sizeof(*sin6)); 80288768458SSam Leffler sin6->sin6_family = AF_INET6; 80388768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 80488768458SSam Leffler bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); 80588768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 80688768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 80788768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); 80888768458SSam Leffler } 80988768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 81088768458SSam Leffler 811de47c390SBjoern A. Zeeb return (0); 81288768458SSam Leffler } 81388768458SSam Leffler #endif 81488768458SSam Leffler 815ef91a976SAndrey V. Elsukov int 816ef91a976SAndrey V. Elsukov ipsec_run_hhooks(struct ipsec_ctx_data *ctx, int type) 817ef91a976SAndrey V. Elsukov { 818ef91a976SAndrey V. Elsukov int idx; 819ef91a976SAndrey V. Elsukov 820ef91a976SAndrey V. Elsukov switch (ctx->af) { 821ef91a976SAndrey V. Elsukov #ifdef INET 822ef91a976SAndrey V. Elsukov case AF_INET: 823ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET; 824ef91a976SAndrey V. Elsukov break; 825ef91a976SAndrey V. Elsukov #endif 826ef91a976SAndrey V. Elsukov #ifdef INET6 827ef91a976SAndrey V. Elsukov case AF_INET6: 828ef91a976SAndrey V. Elsukov idx = HHOOK_IPSEC_INET6; 829ef91a976SAndrey V. Elsukov break; 830ef91a976SAndrey V. Elsukov #endif 831ef91a976SAndrey V. Elsukov default: 832ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 833ef91a976SAndrey V. Elsukov } 834ef91a976SAndrey V. Elsukov if (type == HHOOK_TYPE_IPSEC_IN) 835ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_in[idx], ctx, NULL); 836ef91a976SAndrey V. Elsukov else 837ef91a976SAndrey V. Elsukov HHOOKS_RUN_IF(V_ipsec_hhh_out[idx], ctx, NULL); 838ef91a976SAndrey V. Elsukov if (*ctx->mp == NULL) 839ef91a976SAndrey V. Elsukov return (EACCES); 840ef91a976SAndrey V. Elsukov return (0); 841ef91a976SAndrey V. Elsukov } 842ef91a976SAndrey V. Elsukov 84388768458SSam Leffler static void 844cd1a38f5SBjoern A. Zeeb ipsec_delpcbpolicy(struct inpcbpolicy *p) 84588768458SSam Leffler { 846de47c390SBjoern A. Zeeb 8476464079fSSam Leffler free(p, M_IPSEC_INPCB); 84888768458SSam Leffler } 84988768458SSam Leffler 850de47c390SBjoern A. Zeeb /* Initialize policy in PCB. */ 85188768458SSam Leffler int 852cd1a38f5SBjoern A. Zeeb ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) 85388768458SSam Leffler { 85488768458SSam Leffler struct inpcbpolicy *new; 85588768458SSam Leffler 856de47c390SBjoern A. Zeeb /* Sanity check. */ 85788768458SSam Leffler if (so == NULL || pcb_sp == NULL) 8589ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 85988768458SSam Leffler 86088768458SSam Leffler new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), 8616464079fSSam Leffler M_IPSEC_INPCB, M_NOWAIT|M_ZERO); 86288768458SSam Leffler if (new == NULL) { 8639ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 864de47c390SBjoern A. Zeeb return (ENOBUFS); 86588768458SSam Leffler } 86688768458SSam Leffler 8679ffa9677SSam Leffler new->priv = IPSEC_IS_PRIVILEGED_SO(so); 86888768458SSam Leffler 86988768458SSam Leffler if ((new->sp_in = KEY_NEWSP()) == NULL) { 87088768458SSam Leffler ipsec_delpcbpolicy(new); 871de47c390SBjoern A. Zeeb return (ENOBUFS); 87288768458SSam Leffler } 87388768458SSam Leffler new->sp_in->policy = IPSEC_POLICY_ENTRUST; 87488768458SSam Leffler if ((new->sp_out = KEY_NEWSP()) == NULL) { 87588768458SSam Leffler KEY_FREESP(&new->sp_in); 87688768458SSam Leffler ipsec_delpcbpolicy(new); 877de47c390SBjoern A. Zeeb return (ENOBUFS); 87888768458SSam Leffler } 87988768458SSam Leffler new->sp_out->policy = IPSEC_POLICY_ENTRUST; 88088768458SSam Leffler *pcb_sp = new; 88188768458SSam Leffler 882de47c390SBjoern A. Zeeb return (0); 88388768458SSam Leffler } 88488768458SSam Leffler 885de47c390SBjoern A. Zeeb /* Copy old IPsec policy into new. */ 88688768458SSam Leffler int 887cd1a38f5SBjoern A. Zeeb ipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new) 88888768458SSam Leffler { 88988768458SSam Leffler struct secpolicy *sp; 89088768458SSam Leffler 89188768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_in); 89288768458SSam Leffler if (sp) { 89388768458SSam Leffler KEY_FREESP(&new->sp_in); 89488768458SSam Leffler new->sp_in = sp; 89588768458SSam Leffler } else 896de47c390SBjoern A. Zeeb return (ENOBUFS); 89788768458SSam Leffler 89888768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_out); 89988768458SSam Leffler if (sp) { 90088768458SSam Leffler KEY_FREESP(&new->sp_out); 90188768458SSam Leffler new->sp_out = sp; 90288768458SSam Leffler } else 903de47c390SBjoern A. Zeeb return (ENOBUFS); 90488768458SSam Leffler 90588768458SSam Leffler new->priv = old->priv; 90688768458SSam Leffler 907de47c390SBjoern A. Zeeb return (0); 90888768458SSam Leffler } 90988768458SSam Leffler 9106464079fSSam Leffler struct ipsecrequest * 9116464079fSSam Leffler ipsec_newisr(void) 9126464079fSSam Leffler { 9136464079fSSam Leffler struct ipsecrequest *p; 9146464079fSSam Leffler 9156464079fSSam Leffler p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); 9166464079fSSam Leffler if (p != NULL) 9179ffa9677SSam Leffler IPSECREQUEST_LOCK_INIT(p); 918de47c390SBjoern A. Zeeb return (p); 9196464079fSSam Leffler } 9206464079fSSam Leffler 9216464079fSSam Leffler void 9226464079fSSam Leffler ipsec_delisr(struct ipsecrequest *p) 9236464079fSSam Leffler { 924de47c390SBjoern A. Zeeb 9259ffa9677SSam Leffler IPSECREQUEST_LOCK_DESTROY(p); 9266464079fSSam Leffler free(p, M_IPSEC_SR); 9276464079fSSam Leffler } 9286464079fSSam Leffler 929de47c390SBjoern A. Zeeb /* Deep-copy a policy in PCB. */ 93088768458SSam Leffler static struct secpolicy * 931cd1a38f5SBjoern A. Zeeb ipsec_deepcopy_policy(struct secpolicy *src) 93288768458SSam Leffler { 93388768458SSam Leffler struct ipsecrequest *newchain = NULL; 93488768458SSam Leffler struct ipsecrequest *p; 93588768458SSam Leffler struct ipsecrequest **q; 93688768458SSam Leffler struct ipsecrequest *r; 93788768458SSam Leffler struct secpolicy *dst; 93888768458SSam Leffler 93988768458SSam Leffler if (src == NULL) 940de47c390SBjoern A. Zeeb return (NULL); 94188768458SSam Leffler dst = KEY_NEWSP(); 94288768458SSam Leffler if (dst == NULL) 943de47c390SBjoern A. Zeeb return (NULL); 94488768458SSam Leffler 94588768458SSam Leffler /* 946de47c390SBjoern A. Zeeb * Deep-copy IPsec request chain. This is required since struct 94788768458SSam Leffler * ipsecrequest is not reference counted. 94888768458SSam Leffler */ 94988768458SSam Leffler q = &newchain; 95088768458SSam Leffler for (p = src->req; p; p = p->next) { 9516464079fSSam Leffler *q = ipsec_newisr(); 95288768458SSam Leffler if (*q == NULL) 95388768458SSam Leffler goto fail; 95488768458SSam Leffler (*q)->saidx.proto = p->saidx.proto; 95588768458SSam Leffler (*q)->saidx.mode = p->saidx.mode; 95688768458SSam Leffler (*q)->level = p->level; 95788768458SSam Leffler (*q)->saidx.reqid = p->saidx.reqid; 95888768458SSam Leffler 95988768458SSam Leffler bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); 96088768458SSam Leffler bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); 96188768458SSam Leffler 96288768458SSam Leffler (*q)->sp = dst; 96388768458SSam Leffler 96488768458SSam Leffler q = &((*q)->next); 96588768458SSam Leffler } 96688768458SSam Leffler 96788768458SSam Leffler dst->req = newchain; 96888768458SSam Leffler dst->policy = src->policy; 969de47c390SBjoern A. Zeeb /* Do not touch the refcnt fields. */ 97088768458SSam Leffler 971de47c390SBjoern A. Zeeb return (dst); 97288768458SSam Leffler 97388768458SSam Leffler fail: 97488768458SSam Leffler for (p = newchain; p; p = r) { 97588768458SSam Leffler r = p->next; 9766464079fSSam Leffler ipsec_delisr(p); 97788768458SSam Leffler p = NULL; 97888768458SSam Leffler } 9795a8c498fSConrad Meyer KEY_FREESP(&dst); 980de47c390SBjoern A. Zeeb return (NULL); 98188768458SSam Leffler } 98288768458SSam Leffler 983de47c390SBjoern A. Zeeb /* Set policy and IPsec request if present. */ 98488768458SSam Leffler static int 98597aa4a51SBjoern A. Zeeb ipsec_set_policy_internal(struct secpolicy **pcb_sp, int optname, 98697aa4a51SBjoern A. Zeeb caddr_t request, size_t len, struct ucred *cred) 98788768458SSam Leffler { 98888768458SSam Leffler struct sadb_x_policy *xpl; 98988768458SSam Leffler struct secpolicy *newsp = NULL; 99088768458SSam Leffler int error; 99188768458SSam Leffler 992de47c390SBjoern A. Zeeb /* Sanity check. */ 99388768458SSam Leffler if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) 994de47c390SBjoern A. Zeeb return (EINVAL); 99588768458SSam Leffler if (len < sizeof(*xpl)) 996de47c390SBjoern A. Zeeb return (EINVAL); 99788768458SSam Leffler xpl = (struct sadb_x_policy *)request; 99888768458SSam Leffler 99988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10009ffa9677SSam Leffler printf("%s: passed policy\n", __func__); 100188768458SSam Leffler kdebug_sadb_x_policy((struct sadb_ext *)xpl)); 100288768458SSam Leffler 1003de47c390SBjoern A. Zeeb /* Check policy type. */ 100497aa4a51SBjoern A. Zeeb /* ipsec_set_policy_internal() accepts IPSEC, ENTRUST and BYPASS. */ 100588768458SSam Leffler if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD 100688768458SSam Leffler || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) 1007de47c390SBjoern A. Zeeb return (EINVAL); 100888768458SSam Leffler 1009de47c390SBjoern A. Zeeb /* Check privileged socket. */ 1010c26fe973SBjoern A. Zeeb if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { 1011c26fe973SBjoern A. Zeeb error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); 1012c26fe973SBjoern A. Zeeb if (error) 1013de47c390SBjoern A. Zeeb return (EACCES); 1014c26fe973SBjoern A. Zeeb } 101588768458SSam Leffler 1016de47c390SBjoern A. Zeeb /* Allocating new SP entry. */ 101788768458SSam Leffler if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) 1018de47c390SBjoern A. Zeeb return (error); 101988768458SSam Leffler 1020de47c390SBjoern A. Zeeb /* Clear old SP and set new SP. */ 102188768458SSam Leffler KEY_FREESP(pcb_sp); 102288768458SSam Leffler *pcb_sp = newsp; 102388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10249ffa9677SSam Leffler printf("%s: new policy\n", __func__); 102588768458SSam Leffler kdebug_secpolicy(newsp)); 102688768458SSam Leffler 1027de47c390SBjoern A. Zeeb return (0); 102888768458SSam Leffler } 102988768458SSam Leffler 103088768458SSam Leffler int 103197aa4a51SBjoern A. Zeeb ipsec_set_policy(struct inpcb *inp, int optname, caddr_t request, 1032cd1a38f5SBjoern A. Zeeb size_t len, struct ucred *cred) 103388768458SSam Leffler { 103488768458SSam Leffler struct sadb_x_policy *xpl; 103588768458SSam Leffler struct secpolicy **pcb_sp; 103688768458SSam Leffler 1037de47c390SBjoern A. Zeeb /* Sanity check. */ 103888768458SSam Leffler if (inp == NULL || request == NULL) 1039de47c390SBjoern A. Zeeb return (EINVAL); 104088768458SSam Leffler if (len < sizeof(*xpl)) 1041de47c390SBjoern A. Zeeb return (EINVAL); 104288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 104388768458SSam Leffler 1044de47c390SBjoern A. Zeeb /* Select direction. */ 104588768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 104688768458SSam Leffler case IPSEC_DIR_INBOUND: 104788768458SSam Leffler pcb_sp = &inp->inp_sp->sp_in; 104888768458SSam Leffler break; 104988768458SSam Leffler case IPSEC_DIR_OUTBOUND: 105088768458SSam Leffler pcb_sp = &inp->inp_sp->sp_out; 105188768458SSam Leffler break; 105288768458SSam Leffler default: 10539ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 105488768458SSam Leffler xpl->sadb_x_policy_dir)); 1055de47c390SBjoern A. Zeeb return (EINVAL); 105688768458SSam Leffler } 105788768458SSam Leffler 105897aa4a51SBjoern A. Zeeb return (ipsec_set_policy_internal(pcb_sp, optname, request, len, cred)); 105988768458SSam Leffler } 106088768458SSam Leffler 106188768458SSam Leffler int 106297aa4a51SBjoern A. Zeeb ipsec_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1063cd1a38f5SBjoern A. Zeeb struct mbuf **mp) 106488768458SSam Leffler { 106588768458SSam Leffler struct sadb_x_policy *xpl; 106688768458SSam Leffler struct secpolicy *pcb_sp; 106788768458SSam Leffler 1068de47c390SBjoern A. Zeeb /* Sanity check. */ 106988768458SSam Leffler if (inp == NULL || request == NULL || mp == NULL) 1070de47c390SBjoern A. Zeeb return (EINVAL); 10719ffa9677SSam Leffler IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 107288768458SSam Leffler if (len < sizeof(*xpl)) 1073de47c390SBjoern A. Zeeb return (EINVAL); 107488768458SSam Leffler xpl = (struct sadb_x_policy *)request; 107588768458SSam Leffler 1076de47c390SBjoern A. Zeeb /* Select direction. */ 107788768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 107888768458SSam Leffler case IPSEC_DIR_INBOUND: 107988768458SSam Leffler pcb_sp = inp->inp_sp->sp_in; 108088768458SSam Leffler break; 108188768458SSam Leffler case IPSEC_DIR_OUTBOUND: 108288768458SSam Leffler pcb_sp = inp->inp_sp->sp_out; 108388768458SSam Leffler break; 108488768458SSam Leffler default: 10859ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 108688768458SSam Leffler xpl->sadb_x_policy_dir)); 1087de47c390SBjoern A. Zeeb return (EINVAL); 108888768458SSam Leffler } 108988768458SSam Leffler 109097aa4a51SBjoern A. Zeeb /* Sanity check. Should be an IPSEC_ASSERT. */ 109197aa4a51SBjoern A. Zeeb if (pcb_sp == NULL) 109297aa4a51SBjoern A. Zeeb return (EINVAL); 109397aa4a51SBjoern A. Zeeb 109497aa4a51SBjoern A. Zeeb *mp = key_sp2msg(pcb_sp); 109597aa4a51SBjoern A. Zeeb if (!*mp) { 109697aa4a51SBjoern A. Zeeb ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 109797aa4a51SBjoern A. Zeeb return (ENOBUFS); 109897aa4a51SBjoern A. Zeeb } 109997aa4a51SBjoern A. Zeeb 110097aa4a51SBjoern A. Zeeb (*mp)->m_type = MT_DATA; 110197aa4a51SBjoern A. Zeeb KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 110297aa4a51SBjoern A. Zeeb printf("%s:\n", __func__); kdebug_mbuf(*mp)); 110397aa4a51SBjoern A. Zeeb 110497aa4a51SBjoern A. Zeeb return (0); 110588768458SSam Leffler } 110688768458SSam Leffler 1107de47c390SBjoern A. Zeeb /* Delete policy in PCB. */ 110888768458SSam Leffler int 1109cd1a38f5SBjoern A. Zeeb ipsec_delete_pcbpolicy(struct inpcb *inp) 111088768458SSam Leffler { 11119ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inp")); 111288768458SSam Leffler 111388768458SSam Leffler if (inp->inp_sp == NULL) 1114de47c390SBjoern A. Zeeb return (0); 111588768458SSam Leffler 111688768458SSam Leffler if (inp->inp_sp->sp_in != NULL) 111788768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_in); 111888768458SSam Leffler 111988768458SSam Leffler if (inp->inp_sp->sp_out != NULL) 112088768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_out); 112188768458SSam Leffler 112288768458SSam Leffler ipsec_delpcbpolicy(inp->inp_sp); 112388768458SSam Leffler inp->inp_sp = NULL; 112488768458SSam Leffler 1125de47c390SBjoern A. Zeeb return (0); 112688768458SSam Leffler } 112788768458SSam Leffler 112888768458SSam Leffler /* 1129de47c390SBjoern A. Zeeb * Return current level. 113088768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 113188768458SSam Leffler */ 113288768458SSam Leffler u_int 1133cd1a38f5SBjoern A. Zeeb ipsec_get_reqlevel(struct ipsecrequest *isr) 113488768458SSam Leffler { 113588768458SSam Leffler u_int level = 0; 113688768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 113788768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 113888768458SSam Leffler 11399ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); 11409ffa9677SSam Leffler IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, 11419ffa9677SSam Leffler ("af family mismatch, src %u, dst %u", 114288768458SSam Leffler isr->sp->spidx.src.sa.sa_family, 114388768458SSam Leffler isr->sp->spidx.dst.sa.sa_family)); 114488768458SSam Leffler 1145de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */ 114688768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 114788768458SSam Leffler (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ 114888768458SSam Leffler && (lev) != IPSEC_LEVEL_UNIQUE) \ 1149603724d3SBjoern A. Zeeb ? (V_ipsec_debug \ 115088768458SSam Leffler ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 115188768458SSam Leffler (lev), IPSEC_LEVEL_REQUIRE) \ 115288768458SSam Leffler : 0), \ 115388768458SSam Leffler (lev) = IPSEC_LEVEL_REQUIRE, \ 115488768458SSam Leffler (lev) \ 115588768458SSam Leffler : (lev)) 115688768458SSam Leffler 1157de47c390SBjoern A. Zeeb /* Set default level. */ 115888768458SSam Leffler switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { 115988768458SSam Leffler #ifdef INET 116088768458SSam Leffler case AF_INET: 1161603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 1162603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 1163603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 1164603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 116588768458SSam Leffler break; 116688768458SSam Leffler #endif 116788768458SSam Leffler #ifdef INET6 116888768458SSam Leffler case AF_INET6: 1169603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 1170603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 1171603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 1172603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 117388768458SSam Leffler break; 117488768458SSam Leffler #endif /* INET6 */ 117588768458SSam Leffler default: 11769ffa9677SSam Leffler panic("%s: unknown af %u", 11779ffa9677SSam Leffler __func__, isr->sp->spidx.src.sa.sa_family); 117888768458SSam Leffler } 117988768458SSam Leffler 118088768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 118188768458SSam Leffler 1182de47c390SBjoern A. Zeeb /* Set level. */ 118388768458SSam Leffler switch (isr->level) { 118488768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 118588768458SSam Leffler switch (isr->saidx.proto) { 118688768458SSam Leffler case IPPROTO_ESP: 118788768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 118888768458SSam Leffler level = esp_net_deflev; 118988768458SSam Leffler else 119088768458SSam Leffler level = esp_trans_deflev; 119188768458SSam Leffler break; 119288768458SSam Leffler case IPPROTO_AH: 119388768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 119488768458SSam Leffler level = ah_net_deflev; 119588768458SSam Leffler else 119688768458SSam Leffler level = ah_trans_deflev; 11978381996eSSam Leffler break; 119888768458SSam Leffler case IPPROTO_IPCOMP: 119988768458SSam Leffler /* 1200de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document says that 1201de47c390SBjoern A. Zeeb * we shouldn't compress small packets. 120288768458SSam Leffler */ 120388768458SSam Leffler level = IPSEC_LEVEL_USE; 120488768458SSam Leffler break; 120588768458SSam Leffler default: 12069ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 120788768458SSam Leffler isr->saidx.proto); 120888768458SSam Leffler } 120988768458SSam Leffler break; 121088768458SSam Leffler 121188768458SSam Leffler case IPSEC_LEVEL_USE: 121288768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 121388768458SSam Leffler level = isr->level; 121488768458SSam Leffler break; 121588768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 121688768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 121788768458SSam Leffler break; 121888768458SSam Leffler 121988768458SSam Leffler default: 12209ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 122188768458SSam Leffler } 122288768458SSam Leffler 1223de47c390SBjoern A. Zeeb return (level); 122488768458SSam Leffler } 122588768458SSam Leffler 122688768458SSam Leffler /* 122788768458SSam Leffler * Check security policy requirements against the actual 122888768458SSam Leffler * packet contents. Return one if the packet should be 122988768458SSam Leffler * reject as "invalid"; otherwiser return zero to have the 123088768458SSam Leffler * packet treated as "valid". 123188768458SSam Leffler * 123288768458SSam Leffler * OUT: 123388768458SSam Leffler * 0: valid 123488768458SSam Leffler * 1: invalid 123588768458SSam Leffler */ 1236a9b9f6b6SAndrey V. Elsukov static int 1237efb10c3cSAndrey V. Elsukov ipsec_in_reject(struct secpolicy *sp, const struct mbuf *m) 123888768458SSam Leffler { 123988768458SSam Leffler struct ipsecrequest *isr; 124088768458SSam Leffler int need_auth; 124188768458SSam Leffler 124288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 12439ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 124488768458SSam Leffler 1245de47c390SBjoern A. Zeeb /* Check policy. */ 124688768458SSam Leffler switch (sp->policy) { 124788768458SSam Leffler case IPSEC_POLICY_DISCARD: 1248de47c390SBjoern A. Zeeb return (1); 124988768458SSam Leffler case IPSEC_POLICY_BYPASS: 125088768458SSam Leffler case IPSEC_POLICY_NONE: 1251de47c390SBjoern A. Zeeb return (0); 125288768458SSam Leffler } 125388768458SSam Leffler 12549ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 12559ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 125688768458SSam Leffler 1257de47c390SBjoern A. Zeeb /* XXX Should compare policy against IPsec header history. */ 125888768458SSam Leffler 125988768458SSam Leffler need_auth = 0; 126088768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 126188768458SSam Leffler if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) 126288768458SSam Leffler continue; 126388768458SSam Leffler switch (isr->saidx.proto) { 126488768458SSam Leffler case IPPROTO_ESP: 126588768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 126688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12679ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 126888768458SSam Leffler m->m_flags)); 1269de47c390SBjoern A. Zeeb return (1); 127088768458SSam Leffler } 127188768458SSam Leffler 127288768458SSam Leffler if (!need_auth && 127388768458SSam Leffler isr->sav != NULL && 127488768458SSam Leffler isr->sav->tdb_authalgxform != NULL && 127588768458SSam Leffler (m->m_flags & M_AUTHIPDGM) == 0) { 127688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12779ffa9677SSam Leffler printf("%s: ESP/AH m_flags:%x\n", __func__, 127888768458SSam Leffler m->m_flags)); 1279de47c390SBjoern A. Zeeb return (1); 128088768458SSam Leffler } 128188768458SSam Leffler break; 128288768458SSam Leffler case IPPROTO_AH: 128388768458SSam Leffler need_auth = 1; 128488768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 128588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12869ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 128788768458SSam Leffler m->m_flags)); 1288de47c390SBjoern A. Zeeb return (1); 128988768458SSam Leffler } 129088768458SSam Leffler break; 129188768458SSam Leffler case IPPROTO_IPCOMP: 129288768458SSam Leffler /* 1293de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document 129488768458SSam Leffler * says that we shouldn't compress small 1295de47c390SBjoern A. Zeeb * packets. IPComp policy should always be 129688768458SSam Leffler * treated as being in "use" level. 129788768458SSam Leffler */ 129888768458SSam Leffler break; 129988768458SSam Leffler } 130088768458SSam Leffler } 1301de47c390SBjoern A. Zeeb return (0); /* Valid. */ 130288768458SSam Leffler } 130388768458SSam Leffler 1304a91150daSAndrey V. Elsukov /* 1305a91150daSAndrey V. Elsukov * Non zero return value means security policy DISCARD or policy violation. 1306a91150daSAndrey V. Elsukov */ 130797aa4a51SBjoern A. Zeeb static int 1308efb10c3cSAndrey V. Elsukov ipsec46_in_reject(const struct mbuf *m, struct inpcb *inp) 130988768458SSam Leffler { 131088768458SSam Leffler struct secpolicy *sp; 131188768458SSam Leffler int error; 131288768458SSam Leffler int result; 131388768458SSam Leffler 131426882b42SGeorge V. Neville-Neil if (!key_havesp(IPSEC_DIR_INBOUND)) 131526882b42SGeorge V. Neville-Neil return 0; 131626882b42SGeorge V. Neville-Neil 13179ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 131888768458SSam Leffler 13190275b2e3SAndrey V. Elsukov /* Get SP for this packet. */ 132088768458SSam Leffler if (inp == NULL) 13210275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, &error); 132288768458SSam Leffler else 132388768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 132488768458SSam Leffler 132588768458SSam Leffler if (sp != NULL) { 132688768458SSam Leffler result = ipsec_in_reject(sp, m); 132788768458SSam Leffler KEY_FREESP(&sp); 132888768458SSam Leffler } else { 1329a91150daSAndrey V. Elsukov result = 1; /* treat errors as policy violation */ 133088768458SSam Leffler } 1331de47c390SBjoern A. Zeeb return (result); 133288768458SSam Leffler } 133388768458SSam Leffler 133497aa4a51SBjoern A. Zeeb /* 133597aa4a51SBjoern A. Zeeb * Check AH/ESP integrity. 133697aa4a51SBjoern A. Zeeb * This function is called from tcp_input(), udp_input(), 133797aa4a51SBjoern A. Zeeb * and {ah,esp}4_input for tunnel mode. 133897aa4a51SBjoern A. Zeeb */ 133997aa4a51SBjoern A. Zeeb int 1340efb10c3cSAndrey V. Elsukov ipsec4_in_reject(const struct mbuf *m, struct inpcb *inp) 134197aa4a51SBjoern A. Zeeb { 134297aa4a51SBjoern A. Zeeb int result; 134397aa4a51SBjoern A. Zeeb 134497aa4a51SBjoern A. Zeeb result = ipsec46_in_reject(m, inp); 134597aa4a51SBjoern A. Zeeb if (result) 13466659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_in_polvio); 134797aa4a51SBjoern A. Zeeb 134897aa4a51SBjoern A. Zeeb return (result); 134997aa4a51SBjoern A. Zeeb } 135097aa4a51SBjoern A. Zeeb 135188768458SSam Leffler #ifdef INET6 135288768458SSam Leffler /* 135388768458SSam Leffler * Check AH/ESP integrity. 135488768458SSam Leffler * This function is called from tcp6_input(), udp6_input(), 1355de47c390SBjoern A. Zeeb * and {ah,esp}6_input for tunnel mode. 135688768458SSam Leffler */ 135788768458SSam Leffler int 1358efb10c3cSAndrey V. Elsukov ipsec6_in_reject(const struct mbuf *m, struct inpcb *inp) 135988768458SSam Leffler { 136088768458SSam Leffler int result; 136188768458SSam Leffler 136297aa4a51SBjoern A. Zeeb result = ipsec46_in_reject(m, inp); 136388768458SSam Leffler if (result) 13646659296cSAndrey V. Elsukov IPSEC6STAT_INC(ips_in_polvio); 136597aa4a51SBjoern A. Zeeb 1366de47c390SBjoern A. Zeeb return (result); 136788768458SSam Leffler } 136888768458SSam Leffler #endif 136988768458SSam Leffler 137088768458SSam Leffler /* 1371de47c390SBjoern A. Zeeb * Compute the byte size to be occupied by IPsec header. 1372de47c390SBjoern A. Zeeb * In case it is tunnelled, it includes the size of outer IP header. 1373de47c390SBjoern A. Zeeb * NOTE: SP passed is freed in this function. 137488768458SSam Leffler */ 137588768458SSam Leffler static size_t 137697aa4a51SBjoern A. Zeeb ipsec_hdrsiz_internal(struct secpolicy *sp) 137788768458SSam Leffler { 137888768458SSam Leffler struct ipsecrequest *isr; 13791f8bd75eSBjoern A. Zeeb size_t size; 138088768458SSam Leffler 138188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 13829ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 138388768458SSam Leffler 138488768458SSam Leffler switch (sp->policy) { 138588768458SSam Leffler case IPSEC_POLICY_DISCARD: 138688768458SSam Leffler case IPSEC_POLICY_BYPASS: 138788768458SSam Leffler case IPSEC_POLICY_NONE: 1388de47c390SBjoern A. Zeeb return (0); 138988768458SSam Leffler } 139088768458SSam Leffler 13919ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 13929ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 139388768458SSam Leffler 13941f8bd75eSBjoern A. Zeeb size = 0; 139588768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 139688768458SSam Leffler size_t clen = 0; 139788768458SSam Leffler 139888768458SSam Leffler switch (isr->saidx.proto) { 139988768458SSam Leffler case IPPROTO_ESP: 140088768458SSam Leffler clen = esp_hdrsiz(isr->sav); 140188768458SSam Leffler break; 140288768458SSam Leffler case IPPROTO_AH: 140388768458SSam Leffler clen = ah_hdrsiz(isr->sav); 140488768458SSam Leffler break; 140588768458SSam Leffler case IPPROTO_IPCOMP: 140688768458SSam Leffler clen = sizeof(struct ipcomp); 140788768458SSam Leffler break; 140888768458SSam Leffler } 140988768458SSam Leffler 141088768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 141188768458SSam Leffler switch (isr->saidx.dst.sa.sa_family) { 141288768458SSam Leffler case AF_INET: 141388768458SSam Leffler clen += sizeof(struct ip); 141488768458SSam Leffler break; 141588768458SSam Leffler #ifdef INET6 141688768458SSam Leffler case AF_INET6: 141788768458SSam Leffler clen += sizeof(struct ip6_hdr); 141888768458SSam Leffler break; 141988768458SSam Leffler #endif 142088768458SSam Leffler default: 14219ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 14229ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 142388768458SSam Leffler ((struct sockaddr *)&isr->saidx.dst)->sa_family)); 142488768458SSam Leffler break; 142588768458SSam Leffler } 142688768458SSam Leffler } 14271f8bd75eSBjoern A. Zeeb size += clen; 142888768458SSam Leffler } 142988768458SSam Leffler 14301f8bd75eSBjoern A. Zeeb return (size); 143188768458SSam Leffler } 143288768458SSam Leffler 143397aa4a51SBjoern A. Zeeb /* 143497aa4a51SBjoern A. Zeeb * This function is called from ipsec_hdrsiz_tcp(), ip_ipsec_mtu(), 143597aa4a51SBjoern A. Zeeb * disabled ip6_ipsec_mtu() and ip6_forward(). 143697aa4a51SBjoern A. Zeeb */ 143788768458SSam Leffler size_t 1438efb10c3cSAndrey V. Elsukov ipsec_hdrsiz(const struct mbuf *m, u_int dir, struct inpcb *inp) 143988768458SSam Leffler { 144088768458SSam Leffler struct secpolicy *sp; 144188768458SSam Leffler int error; 144288768458SSam Leffler size_t size; 144388768458SSam Leffler 144426882b42SGeorge V. Neville-Neil if (!key_havesp(dir)) 144526882b42SGeorge V. Neville-Neil return 0; 144626882b42SGeorge V. Neville-Neil 14479ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 144888768458SSam Leffler 14490275b2e3SAndrey V. Elsukov /* Get SP for this packet. */ 145088768458SSam Leffler if (inp == NULL) 14510275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, dir, &error); 145288768458SSam Leffler else 145388768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, &error); 145488768458SSam Leffler 145588768458SSam Leffler if (sp != NULL) { 145697aa4a51SBjoern A. Zeeb size = ipsec_hdrsiz_internal(sp); 145788768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 14589ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, 145988768458SSam Leffler (unsigned long)size)); 146088768458SSam Leffler 146188768458SSam Leffler KEY_FREESP(&sp); 146288768458SSam Leffler } else { 1463de47c390SBjoern A. Zeeb size = 0; /* XXX Should be panic? 14644a67e051SBjoern A. Zeeb * -> No, we are called w/o knowing if 14654a67e051SBjoern A. Zeeb * IPsec processing is needed. */ 146688768458SSam Leffler } 1467de47c390SBjoern A. Zeeb return (size); 146888768458SSam Leffler } 146988768458SSam Leffler 147088768458SSam Leffler /* 147188768458SSam Leffler * Check the variable replay window. 147288768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 147388768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 147488768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 147588768458SSam Leffler * beforehand). 147688768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 147788768458SSam Leffler * 1478*bf435626SFabien Thomas * Based on RFC 6479. Blocks are 32 bits unsigned integers 147988768458SSam Leffler */ 1480*bf435626SFabien Thomas 1481*bf435626SFabien Thomas #define IPSEC_BITMAP_INDEX_MASK(w) (w - 1) 1482*bf435626SFabien Thomas #define IPSEC_REDUNDANT_BIT_SHIFTS 5 1483*bf435626SFabien Thomas #define IPSEC_REDUNDANT_BITS (1 << IPSEC_REDUNDANT_BIT_SHIFTS) 1484*bf435626SFabien Thomas #define IPSEC_BITMAP_LOC_MASK (IPSEC_REDUNDANT_BITS - 1) 1485*bf435626SFabien Thomas 148688768458SSam Leffler int 1487cd1a38f5SBjoern A. Zeeb ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) 148888768458SSam Leffler { 148988768458SSam Leffler const struct secreplay *replay; 1490*bf435626SFabien Thomas u_int32_t wsizeb; /* Constant: window size. */ 1491*bf435626SFabien Thomas int ret, index, bit_location; 149288768458SSam Leffler 14939ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 14949ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 149588768458SSam Leffler 1496*bf435626SFabien Thomas SECASVAR_LOCK(sav); 1497*bf435626SFabien Thomas 1498*bf435626SFabien Thomas ret = 0; 149988768458SSam Leffler replay = sav->replay; 150088768458SSam Leffler 1501*bf435626SFabien Thomas /* No need to check replay if disabled. */ 150288768458SSam Leffler if (replay->wsize == 0) 1503*bf435626SFabien Thomas goto allowed; 150488768458SSam Leffler 1505de47c390SBjoern A. Zeeb /* Constant. */ 150688768458SSam Leffler wsizeb = replay->wsize << 3; 150788768458SSam Leffler 1508de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 150988768458SSam Leffler if (seq == 0) 1510*bf435626SFabien Thomas goto end; 151188768458SSam Leffler 1512de47c390SBjoern A. Zeeb /* First time is always okay. */ 151388768458SSam Leffler if (replay->count == 0) 1514*bf435626SFabien Thomas goto allowed; 151588768458SSam Leffler 1516de47c390SBjoern A. Zeeb /* Larger sequences are okay. */ 1517*bf435626SFabien Thomas if (seq > replay->lastseq) 1518*bf435626SFabien Thomas goto allowed; 151988768458SSam Leffler 1520de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 1521*bf435626SFabien Thomas if (replay->lastseq - seq >= wsizeb) 1522*bf435626SFabien Thomas goto end; 152388768458SSam Leffler 1524*bf435626SFabien Thomas /* The sequence is inside the sliding window 1525*bf435626SFabien Thomas * now check the bit in the bitmap 1526*bf435626SFabien Thomas * bit location only depends on the sequence number 1527*bf435626SFabien Thomas */ 1528*bf435626SFabien Thomas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 1529*bf435626SFabien Thomas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS) 1530*bf435626SFabien Thomas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 153188768458SSam Leffler 1532de47c390SBjoern A. Zeeb /* This packet already seen? */ 1533*bf435626SFabien Thomas if ((replay->bitmap)[index] & (1 << bit_location)) 1534*bf435626SFabien Thomas goto end; 153588768458SSam Leffler 1536*bf435626SFabien Thomas allowed: 1537*bf435626SFabien Thomas ret = 1; 1538*bf435626SFabien Thomas end: 1539*bf435626SFabien Thomas SECASVAR_UNLOCK(sav); 1540*bf435626SFabien Thomas 1541*bf435626SFabien Thomas return (ret); 154288768458SSam Leffler } 154388768458SSam Leffler 154488768458SSam Leffler /* 1545de47c390SBjoern A. Zeeb * Check replay counter whether to update or not. 154688768458SSam Leffler * OUT: 0: OK 154788768458SSam Leffler * 1: NG 154888768458SSam Leffler */ 154988768458SSam Leffler int 1550cd1a38f5SBjoern A. Zeeb ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) 155188768458SSam Leffler { 1552962ac6c7SAndrey V. Elsukov char buf[128]; 155388768458SSam Leffler struct secreplay *replay; 1554*bf435626SFabien Thomas u_int32_t wsizeb; /* Constant: window size. */ 1555*bf435626SFabien Thomas int ret, diff, index, bit_location; 155688768458SSam Leffler 15579ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 15589ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 155988768458SSam Leffler 1560*bf435626SFabien Thomas SECASVAR_LOCK(sav); 1561*bf435626SFabien Thomas 1562*bf435626SFabien Thomas ret = 1; 156388768458SSam Leffler replay = sav->replay; 156488768458SSam Leffler 156588768458SSam Leffler if (replay->wsize == 0) 1566de47c390SBjoern A. Zeeb goto ok; /* No need to check replay. */ 156788768458SSam Leffler 1568de47c390SBjoern A. Zeeb /* Constant. */ 156988768458SSam Leffler wsizeb = replay->wsize << 3; 157088768458SSam Leffler 1571de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 157288768458SSam Leffler if (seq == 0) 1573*bf435626SFabien Thomas goto end; 157488768458SSam Leffler 1575*bf435626SFabien Thomas /* The packet is too old, no need to update */ 1576*bf435626SFabien Thomas if (wsizeb + seq < replay->lastseq) 157788768458SSam Leffler goto ok; 157888768458SSam Leffler 1579*bf435626SFabien Thomas /* Now update the bit */ 1580*bf435626SFabien Thomas index = (seq >> IPSEC_REDUNDANT_BIT_SHIFTS); 1581*bf435626SFabien Thomas 1582*bf435626SFabien Thomas /* First check if the sequence number is in the range */ 158388768458SSam Leffler if (seq > replay->lastseq) { 1584*bf435626SFabien Thomas int id; 1585*bf435626SFabien Thomas int index_cur = replay->lastseq >> IPSEC_REDUNDANT_BIT_SHIFTS; 158688768458SSam Leffler 1587*bf435626SFabien Thomas diff = index - index_cur; 1588*bf435626SFabien Thomas if (diff > replay->bitmap_size) { 1589*bf435626SFabien Thomas /* something unusual in this case */ 1590*bf435626SFabien Thomas diff = replay->bitmap_size; 159188768458SSam Leffler } 1592*bf435626SFabien Thomas 1593*bf435626SFabien Thomas for (id = 0; id < diff; ++id) { 1594*bf435626SFabien Thomas replay->bitmap[(id + index_cur + 1) 1595*bf435626SFabien Thomas & IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size)] = 0; 1596*bf435626SFabien Thomas } 1597*bf435626SFabien Thomas 159888768458SSam Leffler replay->lastseq = seq; 159988768458SSam Leffler } 160088768458SSam Leffler 1601*bf435626SFabien Thomas index &= IPSEC_BITMAP_INDEX_MASK(replay->bitmap_size); 1602*bf435626SFabien Thomas bit_location = seq & IPSEC_BITMAP_LOC_MASK; 1603*bf435626SFabien Thomas 1604*bf435626SFabien Thomas /* this packet has already been received */ 1605*bf435626SFabien Thomas if (replay->bitmap[index] & (1 << bit_location)) 1606*bf435626SFabien Thomas goto end; 1607*bf435626SFabien Thomas 1608*bf435626SFabien Thomas replay->bitmap[index] |= (1 << bit_location); 1609*bf435626SFabien Thomas 161088768458SSam Leffler ok: 161188768458SSam Leffler if (replay->count == ~0) { 161288768458SSam Leffler 1613de47c390SBjoern A. Zeeb /* Set overflow flag. */ 161488768458SSam Leffler replay->overflow++; 161588768458SSam Leffler 1616de47c390SBjoern A. Zeeb /* Don't increment, no more packets accepted. */ 161788768458SSam Leffler if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) 1618*bf435626SFabien Thomas goto end; 161988768458SSam Leffler 16209ffa9677SSam Leffler ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 1621962ac6c7SAndrey V. Elsukov __func__, replay->overflow, 1622962ac6c7SAndrey V. Elsukov ipsec_logsastr(sav, buf, sizeof(buf)))); 162388768458SSam Leffler } 162488768458SSam Leffler 1625*bf435626SFabien Thomas ret = 0; 162688768458SSam Leffler 1627*bf435626SFabien Thomas end: 1628*bf435626SFabien Thomas SECASVAR_UNLOCK(sav); 1629*bf435626SFabien Thomas return (ret); 163088768458SSam Leffler } 163188768458SSam Leffler 163288768458SSam Leffler /* Return a printable string for the address. */ 163388768458SSam Leffler char* 1634962ac6c7SAndrey V. Elsukov ipsec_address(union sockaddr_union* sa, char *buf, socklen_t size) 163588768458SSam Leffler { 1636de47c390SBjoern A. Zeeb 163788768458SSam Leffler switch (sa->sa.sa_family) { 163849ddabdfSPawel Jakub Dawidek #ifdef INET 163988768458SSam Leffler case AF_INET: 1640962ac6c7SAndrey V. Elsukov return (inet_ntop(AF_INET, &sa->sin.sin_addr, buf, size)); 164188768458SSam Leffler #endif /* INET */ 164249ddabdfSPawel Jakub Dawidek #ifdef INET6 164388768458SSam Leffler case AF_INET6: 1644962ac6c7SAndrey V. Elsukov return (inet_ntop(AF_INET6, &sa->sin6.sin6_addr, buf, size)); 164588768458SSam Leffler #endif /* INET6 */ 164688768458SSam Leffler default: 1647de47c390SBjoern A. Zeeb return ("(unknown address family)"); 164888768458SSam Leffler } 164988768458SSam Leffler } 165088768458SSam Leffler 1651962ac6c7SAndrey V. Elsukov char * 1652962ac6c7SAndrey V. Elsukov ipsec_logsastr(struct secasvar *sav, char *buf, size_t size) 165388768458SSam Leffler { 1654962ac6c7SAndrey V. Elsukov char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; 165588768458SSam Leffler 1656962ac6c7SAndrey V. Elsukov IPSEC_ASSERT(sav->sah->saidx.src.sa.sa_family == 1657962ac6c7SAndrey V. Elsukov sav->sah->saidx.dst.sa.sa_family, ("address family mismatch")); 165888768458SSam Leffler 1659962ac6c7SAndrey V. Elsukov snprintf(buf, size, "SA(SPI=%08lx src=%s dst=%s)", 1660962ac6c7SAndrey V. Elsukov (u_long)ntohl(sav->spi), 1661962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.src, sbuf, sizeof(sbuf)), 1662962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, dbuf, sizeof(dbuf))); 1663de47c390SBjoern A. Zeeb return (buf); 166488768458SSam Leffler } 166588768458SSam Leffler 166688768458SSam Leffler void 1667efb10c3cSAndrey V. Elsukov ipsec_dumpmbuf(const struct mbuf *m) 166888768458SSam Leffler { 1669efb10c3cSAndrey V. Elsukov const u_char *p; 167088768458SSam Leffler int totlen; 167188768458SSam Leffler int i; 167288768458SSam Leffler 167388768458SSam Leffler totlen = 0; 167488768458SSam Leffler printf("---\n"); 167588768458SSam Leffler while (m) { 1676efb10c3cSAndrey V. Elsukov p = mtod(m, const u_char *); 167788768458SSam Leffler for (i = 0; i < m->m_len; i++) { 167888768458SSam Leffler printf("%02x ", p[i]); 167988768458SSam Leffler totlen++; 168088768458SSam Leffler if (totlen % 16 == 0) 168188768458SSam Leffler printf("\n"); 168288768458SSam Leffler } 168388768458SSam Leffler m = m->m_next; 168488768458SSam Leffler } 168588768458SSam Leffler if (totlen % 16 != 0) 168688768458SSam Leffler printf("\n"); 168788768458SSam Leffler printf("---\n"); 168888768458SSam Leffler } 168988768458SSam Leffler 16908381996eSSam Leffler static void 169193201211SAndrey V. Elsukov def_policy_init(const void *unused __unused) 16921ed81b73SMarko Zec { 16931ed81b73SMarko Zec 169493201211SAndrey V. Elsukov bzero(&V_def_policy, sizeof(struct secpolicy)); 169593201211SAndrey V. Elsukov V_def_policy.policy = IPSEC_POLICY_NONE; 169693201211SAndrey V. Elsukov V_def_policy.refcnt = 1; 16978381996eSSam Leffler } 169889856f7eSBjoern A. Zeeb VNET_SYSINIT(def_policy_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 169993201211SAndrey V. Elsukov def_policy_init, NULL); 17008381996eSSam Leffler 17018381996eSSam Leffler 1702de47c390SBjoern A. Zeeb /* XXX This stuff doesn't belong here... */ 170388768458SSam Leffler 170488768458SSam Leffler static struct xformsw* xforms = NULL; 170588768458SSam Leffler 170688768458SSam Leffler /* 170788768458SSam Leffler * Register a transform; typically at system startup. 170888768458SSam Leffler */ 170988768458SSam Leffler void 171088768458SSam Leffler xform_register(struct xformsw* xsp) 171188768458SSam Leffler { 1712de47c390SBjoern A. Zeeb 171388768458SSam Leffler xsp->xf_next = xforms; 171488768458SSam Leffler xforms = xsp; 171588768458SSam Leffler } 171688768458SSam Leffler 171788768458SSam Leffler /* 171888768458SSam Leffler * Initialize transform support in an sav. 171988768458SSam Leffler */ 172088768458SSam Leffler int 172188768458SSam Leffler xform_init(struct secasvar *sav, int xftype) 172288768458SSam Leffler { 172388768458SSam Leffler struct xformsw *xsp; 172488768458SSam Leffler 1725de47c390SBjoern A. Zeeb if (sav->tdb_xform != NULL) /* Previously initialized. */ 1726de47c390SBjoern A. Zeeb return (0); 172788768458SSam Leffler for (xsp = xforms; xsp; xsp = xsp->xf_next) 172888768458SSam Leffler if (xsp->xf_type == xftype) 1729de47c390SBjoern A. Zeeb return ((*xsp->xf_init)(sav, xsp)); 1730de47c390SBjoern A. Zeeb return (EINVAL); 173188768458SSam Leffler } 1732