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> 5188768458SSam Leffler #include <sys/time.h> 5288768458SSam Leffler #include <sys/kernel.h> 5388768458SSam Leffler #include <sys/syslog.h> 5488768458SSam Leffler #include <sys/sysctl.h> 5588768458SSam Leffler #include <sys/proc.h> 5688768458SSam Leffler 5788768458SSam Leffler #include <net/if.h> 5876039bc8SGleb Smirnoff #include <net/if_var.h> 59eddfbb76SRobert Watson #include <net/vnet.h> 6088768458SSam Leffler 6188768458SSam Leffler #include <netinet/in.h> 6288768458SSam Leffler #include <netinet/in_systm.h> 6388768458SSam Leffler #include <netinet/ip.h> 6488768458SSam Leffler #include <netinet/ip_var.h> 6588768458SSam Leffler #include <netinet/in_var.h> 6688768458SSam Leffler #include <netinet/udp.h> 6788768458SSam Leffler #include <netinet/udp_var.h> 6888768458SSam Leffler #include <netinet/tcp.h> 6988768458SSam Leffler #include <netinet/udp.h> 7088768458SSam Leffler 7188768458SSam Leffler #include <netinet/ip6.h> 7288768458SSam Leffler #ifdef INET6 7388768458SSam Leffler #include <netinet6/ip6_var.h> 7488768458SSam Leffler #endif 7588768458SSam Leffler #include <netinet/in_pcb.h> 7688768458SSam Leffler #ifdef INET6 7788768458SSam Leffler #include <netinet/icmp6.h> 7888768458SSam Leffler #endif 7988768458SSam Leffler 802cb64cb2SGeorge V. Neville-Neil #include <sys/types.h> 8188768458SSam Leffler #include <netipsec/ipsec.h> 8288768458SSam Leffler #ifdef INET6 8388768458SSam Leffler #include <netipsec/ipsec6.h> 8488768458SSam Leffler #endif 8588768458SSam Leffler #include <netipsec/ah_var.h> 8688768458SSam Leffler #include <netipsec/esp_var.h> 8788768458SSam Leffler #include <netipsec/ipcomp.h> /*XXX*/ 8888768458SSam Leffler #include <netipsec/ipcomp_var.h> 8988768458SSam Leffler 9088768458SSam Leffler #include <netipsec/key.h> 9188768458SSam Leffler #include <netipsec/keydb.h> 9288768458SSam Leffler #include <netipsec/key_debug.h> 9388768458SSam Leffler 9488768458SSam Leffler #include <netipsec/xform.h> 9588768458SSam Leffler 9688768458SSam Leffler #include <machine/in_cksum.h> 9788768458SSam Leffler 987aee3dd1SSam Leffler #include <opencrypto/cryptodev.h> 997aee3dd1SSam Leffler 100eddfbb76SRobert Watson #ifdef IPSEC_DEBUG 101eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_debug) = 1; 102eddfbb76SRobert Watson #else 103eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_debug) = 0; 104385195c0SMarko Zec #endif 10582cea7e6SBjoern A. Zeeb 106de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */ 107db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec4stat); 108db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec4stat); 109db8c0879SAndrey V. Elsukov 110db8c0879SAndrey V. Elsukov #ifdef VIMAGE 111db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec4stat); 112db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 113db8c0879SAndrey V. Elsukov 114eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_offsetmask) = 0; /* maybe IP_DF? */ 115eddfbb76SRobert Watson /* DF bit on encap. 0: clear 1: set 2: copy */ 116eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_dfbit) = 0; 117eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE; 118eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE; 119eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE; 120eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE; 121eddfbb76SRobert Watson /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 122eddfbb76SRobert Watson VNET_DEFINE(int, ip4_ipsec_ecn) = 0; 123eddfbb76SRobert Watson VNET_DEFINE(int, ip4_esp_randpad) = -1; 124eddfbb76SRobert Watson 125*93201211SAndrey V. Elsukov static VNET_DEFINE(struct secpolicy, def_policy); 126*93201211SAndrey V. Elsukov #define V_def_policy VNET(def_policy) 12788768458SSam Leffler /* 12888768458SSam Leffler * Crypto support requirements: 12988768458SSam Leffler * 13088768458SSam Leffler * 1 require hardware support 13188768458SSam Leffler * -1 require software support 13288768458SSam Leffler * 0 take anything 13388768458SSam Leffler */ 134eddfbb76SRobert Watson VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 13588768458SSam Leffler 13613a6cf24SBjoern A. Zeeb FEATURE(ipsec, "Internet Protocol Security (IPsec)"); 13713a6cf24SBjoern A. Zeeb #ifdef IPSEC_NAT_T 13813a6cf24SBjoern A. Zeeb FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')"); 13913a6cf24SBjoern A. Zeeb #endif 14013a6cf24SBjoern A. Zeeb 14188768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec); 14288768458SSam Leffler 14388768458SSam Leffler /* net.inet.ipsec */ 1446df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, 145*93201211SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(def_policy).policy, 0, 146be6b1304STom Rhodes "IPsec default policy."); 1476df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1486df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0, 1498b615593SMarko Zec "Default ESP transport mode level"); 1506df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1516df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0, 1528b615593SMarko Zec "Default ESP tunnel mode level."); 1536df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1546df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0, 1558b615593SMarko Zec "AH transfer mode default level."); 1566df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 1576df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0, 1588b615593SMarko Zec "AH tunnel mode default level."); 1596df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, 1606df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, 1613377c961STom Rhodes "If set clear type-of-service field when doing AH computation."); 1626df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask, 1636df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ah_offsetmask), 0, 1643377c961STom Rhodes "If not set clear offset field mask when doing AH computation."); 1656df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit, 1666df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0, 1678b615593SMarko Zec "Do not fragment bit on encap."); 1686df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, 1696df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0, 170be6b1304STom Rhodes "Explicit Congestion Notification handling."); 1716df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, 1726df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_debug), 0, 173be6b1304STom Rhodes "Enable IPsec debugging output when set."); 1746df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support, 1756df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0, 176be6b1304STom Rhodes "Crypto driver selection."); 177db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ipsec, OID_AUTO, ipsecstats, struct ipsecstat, 178db8c0879SAndrey V. Elsukov ipsec4stat, "IPsec IPv4 statistics."); 17988768458SSam Leffler 1806131838bSPawel Jakub Dawidek #ifdef REGRESSION 181dfa9422bSPawel Jakub Dawidek /* 182dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 183dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 184dfa9422bSPawel Jakub Dawidek */ 185eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_replay) = 0; 1866df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, 1876df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0, 188eddfbb76SRobert Watson "Emulate replay attack"); 189dfa9422bSPawel Jakub Dawidek /* 190dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 191dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 192dfa9422bSPawel Jakub Dawidek */ 193eddfbb76SRobert Watson VNET_DEFINE(int, ipsec_integrity) = 0; 1946df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, 1956df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0, 196eddfbb76SRobert Watson "Emulate man-in-the-middle attack"); 1976131838bSPawel Jakub Dawidek #endif 198dfa9422bSPawel Jakub Dawidek 19988768458SSam Leffler #ifdef INET6 200db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipsecstat, ipsec6stat); 201db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipsec6stat); 202db8c0879SAndrey V. Elsukov 203db8c0879SAndrey V. Elsukov #ifdef VIMAGE 204db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipsec6stat); 205db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 206db8c0879SAndrey V. Elsukov 207eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE; 208eddfbb76SRobert Watson VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE; 209eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE; 210eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE; 211eddfbb76SRobert Watson VNET_DEFINE(int, ip6_ipsec_ecn) = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 21288768458SSam Leffler 21388768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6); 21488768458SSam Leffler 21588768458SSam Leffler /* net.inet6.ipsec6 */ 2166df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, 217*93201211SAndrey V. Elsukov CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(def_policy).policy, 0, 2188b615593SMarko Zec "IPsec default policy."); 2196df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 2206df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0, 2218b615593SMarko Zec "Default ESP transport mode level."); 2226df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 2236df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0, 2248b615593SMarko Zec "Default ESP tunnel mode level."); 2256df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 2266df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0, 2278b615593SMarko Zec "AH transfer mode default level."); 2286df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 2296df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0, 2308b615593SMarko Zec "AH tunnel mode default level."); 2316df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, ecn, 2326df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0, 2333377c961STom Rhodes "Explicit Congestion Notification handling."); 2346df8a710SGleb Smirnoff SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, 2356df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ipsec_debug), 0, 236be6b1304STom Rhodes "Enable IPsec debugging output when set."); 237db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet6_ipsec6, IPSECCTL_STATS, ipsecstats, 238db8c0879SAndrey V. Elsukov struct ipsecstat, ipsec6stat, "IPsec IPv6 statistics."); 23988768458SSam Leffler #endif /* INET6 */ 24088768458SSam Leffler 24118961126SAndrey V. Elsukov static int ipsec_setspidx_inpcb(struct mbuf *, struct inpcb *); 24218961126SAndrey V. Elsukov static int ipsec_setspidx(struct mbuf *, struct secpolicyindex *, int); 24318961126SAndrey V. Elsukov static void ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *, int); 24418961126SAndrey V. Elsukov static int ipsec4_setspidx_ipaddr(struct mbuf *, struct secpolicyindex *); 24588768458SSam Leffler #ifdef INET6 24618961126SAndrey V. Elsukov static void ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *, int); 24718961126SAndrey V. Elsukov static int ipsec6_setspidx_ipaddr(struct mbuf *, struct secpolicyindex *); 24888768458SSam Leffler #endif 24918961126SAndrey V. Elsukov static void ipsec_delpcbpolicy(struct inpcbpolicy *); 25018961126SAndrey V. Elsukov static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src); 25118961126SAndrey V. Elsukov static void vshiftl(unsigned char *, int, int); 25288768458SSam Leffler 2536464079fSSam Leffler MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); 2546464079fSSam Leffler 25588768458SSam Leffler /* 25688768458SSam Leffler * Return a held reference to the default SP. 25788768458SSam Leffler */ 25888768458SSam Leffler static struct secpolicy * 25988768458SSam Leffler key_allocsp_default(const char* where, int tag) 26088768458SSam Leffler { 26188768458SSam Leffler struct secpolicy *sp; 26288768458SSam Leffler 26388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 26488768458SSam Leffler printf("DP key_allocsp_default from %s:%u\n", where, tag)); 26588768458SSam Leffler 266*93201211SAndrey V. Elsukov sp = &V_def_policy; 26788768458SSam Leffler if (sp->policy != IPSEC_POLICY_DISCARD && 26888768458SSam Leffler sp->policy != IPSEC_POLICY_NONE) { 26988768458SSam Leffler ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", 27088768458SSam Leffler sp->policy, IPSEC_POLICY_NONE)); 27188768458SSam Leffler sp->policy = IPSEC_POLICY_NONE; 27288768458SSam Leffler } 273422e4f5bSSam Leffler key_addref(sp); 27488768458SSam Leffler 27588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 27688768458SSam Leffler printf("DP key_allocsp_default returns SP:%p (%u)\n", 27788768458SSam Leffler sp, sp->refcnt)); 278de47c390SBjoern A. Zeeb return (sp); 27988768458SSam Leffler } 28088768458SSam Leffler #define KEY_ALLOCSP_DEFAULT() \ 28188768458SSam Leffler key_allocsp_default(__FILE__, __LINE__) 28288768458SSam Leffler 28388768458SSam Leffler /* 28488768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 28588768458SSam Leffler * and return a pointer to SP. 28688768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 28788768458SSam Leffler * 0 : bypass 28888768458SSam Leffler * EACCES : discard packet. 28988768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 29088768458SSam Leffler * others : error occured. 29188768458SSam Leffler * others: a pointer to SP 29288768458SSam Leffler * 29388768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 29488768458SSam Leffler */ 29588768458SSam Leffler struct secpolicy * 29688768458SSam Leffler ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) 29788768458SSam Leffler { 29888768458SSam Leffler struct secpolicy *sp; 29988768458SSam Leffler 3009ffa9677SSam Leffler IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); 3019ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3029ffa9677SSam Leffler ("invalid direction %u", dir)); 30388768458SSam Leffler 30488768458SSam Leffler sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); 30588768458SSam Leffler if (sp == NULL) /*XXX????*/ 30688768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 3079ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 308de47c390SBjoern A. Zeeb return (sp); 30988768458SSam Leffler } 31088768458SSam Leffler 31188768458SSam Leffler /* 31288768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 31388768458SSam Leffler * and return a pointer to SP. 31488768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 31588768458SSam Leffler * 0 : bypass 31688768458SSam Leffler * EACCES : discard packet. 31788768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 31888768458SSam Leffler * others : error occured. 31988768458SSam Leffler * others: a pointer to SP 32088768458SSam Leffler * 32188768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 32288768458SSam Leffler */ 323511080aeSBjoern A. Zeeb static struct secpolicy * 324511080aeSBjoern A. Zeeb ipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp, int *error) 32588768458SSam Leffler { 32697aa4a51SBjoern A. Zeeb struct inpcbpolicy *pcbsp; 327de47c390SBjoern A. Zeeb struct secpolicy *currsp = NULL; /* Policy on socket. */ 32888768458SSam Leffler struct secpolicy *sp; 32988768458SSam Leffler 3309ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 3319ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inpcb")); 3329ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 3339ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3349ffa9677SSam Leffler ("invalid direction %u", dir)); 33588768458SSam Leffler 336de47c390SBjoern A. Zeeb /* Set spidx in pcb. */ 33797aa4a51SBjoern A. Zeeb *error = ipsec_setspidx_inpcb(m, inp); 33888768458SSam Leffler if (*error) 339de47c390SBjoern A. Zeeb return (NULL); 34088768458SSam Leffler 34197aa4a51SBjoern A. Zeeb pcbsp = inp->inp_sp; 3429ffa9677SSam Leffler IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); 34388768458SSam Leffler switch (dir) { 34488768458SSam Leffler case IPSEC_DIR_INBOUND: 34588768458SSam Leffler currsp = pcbsp->sp_in; 34688768458SSam Leffler break; 34788768458SSam Leffler case IPSEC_DIR_OUTBOUND: 34888768458SSam Leffler currsp = pcbsp->sp_out; 34988768458SSam Leffler break; 35088768458SSam Leffler } 3519ffa9677SSam Leffler IPSEC_ASSERT(currsp != NULL, ("null currsp")); 35288768458SSam Leffler 353de47c390SBjoern A. Zeeb if (pcbsp->priv) { /* When privilieged socket. */ 35488768458SSam Leffler switch (currsp->policy) { 35588768458SSam Leffler case IPSEC_POLICY_BYPASS: 35688768458SSam Leffler case IPSEC_POLICY_IPSEC: 357422e4f5bSSam Leffler key_addref(currsp); 35888768458SSam Leffler sp = currsp; 35988768458SSam Leffler break; 36088768458SSam Leffler 36188768458SSam Leffler case IPSEC_POLICY_ENTRUST: 362de47c390SBjoern A. Zeeb /* Look for a policy in SPD. */ 36388768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 364de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found. */ 36588768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 36688768458SSam Leffler break; 36788768458SSam Leffler 36888768458SSam Leffler default: 3699ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", 3709ffa9677SSam Leffler __func__, currsp->policy)); 37188768458SSam Leffler *error = EINVAL; 372de47c390SBjoern A. Zeeb return (NULL); 37388768458SSam Leffler } 374de47c390SBjoern A. Zeeb } else { /* Unpriv, SPD has policy. */ 37588768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 376de47c390SBjoern A. Zeeb if (sp == NULL) { /* No SP found. */ 37788768458SSam Leffler switch (currsp->policy) { 37888768458SSam Leffler case IPSEC_POLICY_BYPASS: 3799ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Illegal policy for " 3809ffa9677SSam Leffler "non-priviliged defined %d\n", 3819ffa9677SSam Leffler __func__, currsp->policy)); 38288768458SSam Leffler *error = EINVAL; 383de47c390SBjoern A. Zeeb return (NULL); 38488768458SSam Leffler 38588768458SSam Leffler case IPSEC_POLICY_ENTRUST: 38688768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 38788768458SSam Leffler break; 38888768458SSam Leffler 38988768458SSam Leffler case IPSEC_POLICY_IPSEC: 390422e4f5bSSam Leffler key_addref(currsp); 39188768458SSam Leffler sp = currsp; 39288768458SSam Leffler break; 39388768458SSam Leffler 39488768458SSam Leffler default: 3959ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for " 3969ffa9677SSam Leffler "PCB %d\n", __func__, currsp->policy)); 39788768458SSam Leffler *error = EINVAL; 398de47c390SBjoern A. Zeeb return (NULL); 39988768458SSam Leffler } 40088768458SSam Leffler } 40188768458SSam Leffler } 4029ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, 4039ffa9677SSam Leffler ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); 40488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 4059ffa9677SSam Leffler printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", 4069ffa9677SSam Leffler __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); 407de47c390SBjoern A. Zeeb return (sp); 40888768458SSam Leffler } 40988768458SSam Leffler 41088768458SSam Leffler /* 41188768458SSam Leffler * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, 41288768458SSam Leffler * and return a pointer to SP. 41388768458SSam Leffler * OUT: positive: a pointer to the entry for security policy leaf matched. 41488768458SSam Leffler * NULL: no apropreate SP found, the following value is set to error. 41588768458SSam Leffler * 0 : bypass 41688768458SSam Leffler * EACCES : discard packet. 41788768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 41888768458SSam Leffler * others : error occured. 41988768458SSam Leffler */ 42088768458SSam Leffler struct secpolicy * 4210275b2e3SAndrey V. Elsukov ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int *error) 42288768458SSam Leffler { 42388768458SSam Leffler struct secpolicyindex spidx; 42488768458SSam Leffler struct secpolicy *sp; 42588768458SSam Leffler 4269ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 4279ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 4289ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 4299ffa9677SSam Leffler ("invalid direction %u", dir)); 43088768458SSam Leffler 43188768458SSam Leffler sp = NULL; 432e65ada3eSAndrey V. Elsukov *error = 0; 43388768458SSam Leffler if (key_havesp(dir)) { 4349d5abbddSJens Schweikhardt /* Make an index to look for a policy. */ 4350275b2e3SAndrey V. Elsukov *error = ipsec_setspidx(m, &spidx, 0); 43688768458SSam Leffler if (*error != 0) { 4370275b2e3SAndrey V. Elsukov DPRINTF(("%s: setpidx failed, dir %u\n", 4380275b2e3SAndrey V. Elsukov __func__, dir)); 439de47c390SBjoern A. Zeeb return (NULL); 44088768458SSam Leffler } 44188768458SSam Leffler spidx.dir = dir; 44288768458SSam Leffler sp = KEY_ALLOCSP(&spidx, dir); 44388768458SSam Leffler } 444de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found, use system default. */ 44588768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 4469ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 447de47c390SBjoern A. Zeeb return (sp); 44888768458SSam Leffler } 44988768458SSam Leffler 45088768458SSam Leffler struct secpolicy * 4510275b2e3SAndrey V. Elsukov ipsec4_checkpolicy(struct mbuf *m, u_int dir, int *error, struct inpcb *inp) 45288768458SSam Leffler { 45388768458SSam Leffler struct secpolicy *sp; 45488768458SSam Leffler 45588768458SSam Leffler *error = 0; 45688768458SSam Leffler if (inp == NULL) 4570275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, dir, error); 45888768458SSam Leffler else 45988768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, error); 46088768458SSam Leffler if (sp == NULL) { 4619ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); 4626659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_inval); 463de47c390SBjoern A. Zeeb return (NULL); 46488768458SSam Leffler } 4659ffa9677SSam Leffler IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); 46688768458SSam Leffler switch (sp->policy) { 46788768458SSam Leffler case IPSEC_POLICY_ENTRUST: 46888768458SSam Leffler default: 4699ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 470de47c390SBjoern A. Zeeb /* FALLTHROUGH */ 47188768458SSam Leffler case IPSEC_POLICY_DISCARD: 4726659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_polvio); 473de47c390SBjoern A. Zeeb *error = -EINVAL; /* Packet is discarded by caller. */ 47488768458SSam Leffler break; 47588768458SSam Leffler case IPSEC_POLICY_BYPASS: 47688768458SSam Leffler case IPSEC_POLICY_NONE: 47788768458SSam Leffler KEY_FREESP(&sp); 478de47c390SBjoern A. Zeeb sp = NULL; /* NB: force NULL result. */ 47988768458SSam Leffler break; 48088768458SSam Leffler case IPSEC_POLICY_IPSEC: 481de47c390SBjoern A. Zeeb if (sp->req == NULL) /* Acquire a SA. */ 48288768458SSam Leffler *error = key_spdacquire(sp); 48388768458SSam Leffler break; 48488768458SSam Leffler } 48588768458SSam Leffler if (*error != 0) { 48688768458SSam Leffler KEY_FREESP(&sp); 48788768458SSam Leffler sp = NULL; 48888768458SSam Leffler } 489de47c390SBjoern A. Zeeb return (sp); 49088768458SSam Leffler } 49188768458SSam Leffler 49288768458SSam Leffler static int 49397aa4a51SBjoern A. Zeeb ipsec_setspidx_inpcb(struct mbuf *m, struct inpcb *inp) 49488768458SSam Leffler { 49588768458SSam Leffler int error; 49688768458SSam Leffler 4971f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp != NULL, ("null inp")); 4981f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 4991f8bd75eSBjoern A. Zeeb IPSEC_ASSERT(inp->inp_sp->sp_out != NULL && inp->inp_sp->sp_in != NULL, 5009ffa9677SSam Leffler ("null sp_in || sp_out")); 50188768458SSam Leffler 5021f8bd75eSBjoern A. Zeeb error = ipsec_setspidx(m, &inp->inp_sp->sp_in->spidx, 1); 50388768458SSam Leffler if (error == 0) { 5041f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 5051f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_out->spidx = inp->inp_sp->sp_in->spidx; 5061f8bd75eSBjoern A. Zeeb inp->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 50788768458SSam Leffler } else { 5081f8bd75eSBjoern A. Zeeb bzero(&inp->inp_sp->sp_in->spidx, 5091f8bd75eSBjoern A. Zeeb sizeof (inp->inp_sp->sp_in->spidx)); 5101f8bd75eSBjoern A. Zeeb bzero(&inp->inp_sp->sp_out->spidx, 5111f8bd75eSBjoern A. Zeeb sizeof (inp->inp_sp->sp_in->spidx)); 51288768458SSam Leffler } 513de47c390SBjoern A. Zeeb return (error); 51488768458SSam Leffler } 51588768458SSam Leffler 51688768458SSam Leffler /* 517de47c390SBjoern A. Zeeb * Configure security policy index (src/dst/proto/sport/dport) 51888768458SSam Leffler * by looking at the content of mbuf. 519de47c390SBjoern A. Zeeb * The caller is responsible for error recovery (like clearing up spidx). 52088768458SSam Leffler */ 52188768458SSam Leffler static int 522cd1a38f5SBjoern A. Zeeb ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) 52388768458SSam Leffler { 52488768458SSam Leffler struct ip *ip = NULL; 52588768458SSam Leffler struct ip ipbuf; 52688768458SSam Leffler u_int v; 52788768458SSam Leffler struct mbuf *n; 52888768458SSam Leffler int len; 52988768458SSam Leffler int error; 53088768458SSam Leffler 5319ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 53288768458SSam Leffler 53388768458SSam Leffler /* 534de47c390SBjoern A. Zeeb * Validate m->m_pkthdr.len. We see incorrect length if we 53588768458SSam Leffler * mistakenly call this function with inconsistent mbuf chain 536de47c390SBjoern A. Zeeb * (like 4.4BSD tcp/udp processing). XXX Should we panic here? 53788768458SSam Leffler */ 53888768458SSam Leffler len = 0; 53988768458SSam Leffler for (n = m; n; n = n->m_next) 54088768458SSam Leffler len += n->m_len; 54188768458SSam Leffler if (m->m_pkthdr.len != len) { 54288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5439ffa9677SSam Leffler printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", 5449ffa9677SSam Leffler __func__, len, m->m_pkthdr.len)); 545de47c390SBjoern A. Zeeb return (EINVAL); 54688768458SSam Leffler } 54788768458SSam Leffler 54888768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip)) { 54988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5509ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v4), ignored.\n", 5519ffa9677SSam Leffler __func__, m->m_pkthdr.len)); 552de47c390SBjoern A. Zeeb return (EINVAL); 55388768458SSam Leffler } 55488768458SSam Leffler 55588768458SSam Leffler if (m->m_len >= sizeof(*ip)) 55688768458SSam Leffler ip = mtod(m, struct ip *); 55788768458SSam Leffler else { 55888768458SSam Leffler m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); 55988768458SSam Leffler ip = &ipbuf; 56088768458SSam Leffler } 56188768458SSam Leffler v = ip->ip_v; 56288768458SSam Leffler switch (v) { 56388768458SSam Leffler case 4: 56488768458SSam Leffler error = ipsec4_setspidx_ipaddr(m, spidx); 56588768458SSam Leffler if (error) 566de47c390SBjoern A. Zeeb return (error); 56788768458SSam Leffler ipsec4_get_ulp(m, spidx, needport); 568de47c390SBjoern A. Zeeb return (0); 56988768458SSam Leffler #ifdef INET6 57088768458SSam Leffler case 6: 57188768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { 57288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5739ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v6), " 5749ffa9677SSam Leffler "ignored\n", __func__, m->m_pkthdr.len)); 575de47c390SBjoern A. Zeeb return (EINVAL); 57688768458SSam Leffler } 57788768458SSam Leffler error = ipsec6_setspidx_ipaddr(m, spidx); 57888768458SSam Leffler if (error) 579de47c390SBjoern A. Zeeb return (error); 58088768458SSam Leffler ipsec6_get_ulp(m, spidx, needport); 581de47c390SBjoern A. Zeeb return (0); 58288768458SSam Leffler #endif 58388768458SSam Leffler default: 58488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5859ffa9677SSam Leffler printf("%s: " "unknown IP version %u, ignored.\n", 5869ffa9677SSam Leffler __func__, v)); 587de47c390SBjoern A. Zeeb return (EINVAL); 58888768458SSam Leffler } 58988768458SSam Leffler } 59088768458SSam Leffler 59188768458SSam Leffler static void 59288768458SSam Leffler ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 59388768458SSam Leffler { 59488768458SSam Leffler u_int8_t nxt; 59588768458SSam Leffler int off; 59688768458SSam Leffler 597de47c390SBjoern A. Zeeb /* Sanity check. */ 5989ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 5999ffa9677SSam Leffler IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); 60088768458SSam Leffler 60187a25418SErmal Luçi if (m->m_len >= sizeof (struct ip)) { 60288768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 6038f134647SGleb Smirnoff if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) 60488768458SSam Leffler goto done; 60588768458SSam Leffler off = ip->ip_hl << 2; 60688768458SSam Leffler nxt = ip->ip_p; 60788768458SSam Leffler } else { 60888768458SSam Leffler struct ip ih; 60988768458SSam Leffler 61088768458SSam Leffler m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 6118f134647SGleb Smirnoff if (ih.ip_off & htons(IP_MF | IP_OFFMASK)) 61288768458SSam Leffler goto done; 61388768458SSam Leffler off = ih.ip_hl << 2; 61488768458SSam Leffler nxt = ih.ip_p; 61588768458SSam Leffler } 61688768458SSam Leffler 61788768458SSam Leffler while (off < m->m_pkthdr.len) { 61888768458SSam Leffler struct ip6_ext ip6e; 61988768458SSam Leffler struct tcphdr th; 62088768458SSam Leffler struct udphdr uh; 62188768458SSam Leffler 62288768458SSam Leffler switch (nxt) { 62388768458SSam Leffler case IPPROTO_TCP: 62488768458SSam Leffler spidx->ul_proto = nxt; 62588768458SSam Leffler if (!needport) 62688768458SSam Leffler goto done_proto; 62788768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 62888768458SSam Leffler goto done; 62988768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 63088768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 63188768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 63288768458SSam Leffler return; 63388768458SSam Leffler case IPPROTO_UDP: 63488768458SSam Leffler spidx->ul_proto = nxt; 63588768458SSam Leffler if (!needport) 63688768458SSam Leffler goto done_proto; 63788768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 63888768458SSam Leffler goto done; 63988768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 64088768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 64188768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 64288768458SSam Leffler return; 64388768458SSam Leffler case IPPROTO_AH: 644afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 64588768458SSam Leffler goto done; 646de47c390SBjoern A. Zeeb /* XXX Sigh, this works but is totally bogus. */ 64788768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 64888768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 64988768458SSam Leffler nxt = ip6e.ip6e_nxt; 65088768458SSam Leffler break; 65188768458SSam Leffler case IPPROTO_ICMP: 65288768458SSam Leffler default: 653de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 65488768458SSam Leffler spidx->ul_proto = nxt; 65588768458SSam Leffler goto done_proto; 65688768458SSam Leffler } 65788768458SSam Leffler } 65888768458SSam Leffler done: 65988768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 66088768458SSam Leffler done_proto: 66188768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 66288768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 66388768458SSam Leffler } 66488768458SSam Leffler 665de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 66688768458SSam Leffler static int 66788768458SSam Leffler ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 66888768458SSam Leffler { 66988768458SSam Leffler static const struct sockaddr_in template = { 67088768458SSam Leffler sizeof (struct sockaddr_in), 67188768458SSam Leffler AF_INET, 67288768458SSam Leffler 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 67388768458SSam Leffler }; 67488768458SSam Leffler 67588768458SSam Leffler spidx->src.sin = template; 67688768458SSam Leffler spidx->dst.sin = template; 67788768458SSam Leffler 67888768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 67988768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_src), 68088768458SSam Leffler sizeof (struct in_addr), 68188768458SSam Leffler (caddr_t) &spidx->src.sin.sin_addr); 68288768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_dst), 68388768458SSam Leffler sizeof (struct in_addr), 68488768458SSam Leffler (caddr_t) &spidx->dst.sin.sin_addr); 68588768458SSam Leffler } else { 68688768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 68788768458SSam Leffler spidx->src.sin.sin_addr = ip->ip_src; 68888768458SSam Leffler spidx->dst.sin.sin_addr = ip->ip_dst; 68988768458SSam Leffler } 69088768458SSam Leffler 69188768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 69288768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 69388768458SSam Leffler 694de47c390SBjoern A. Zeeb return (0); 69588768458SSam Leffler } 69688768458SSam Leffler 69788768458SSam Leffler #ifdef INET6 69888768458SSam Leffler static void 699cd1a38f5SBjoern A. Zeeb ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 70088768458SSam Leffler { 70188768458SSam Leffler int off, nxt; 70288768458SSam Leffler struct tcphdr th; 70388768458SSam Leffler struct udphdr uh; 7040e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 70588768458SSam Leffler 706de47c390SBjoern A. Zeeb /* Sanity check. */ 70788768458SSam Leffler if (m == NULL) 7089ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 70988768458SSam Leffler 71088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 7119ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(m)); 71288768458SSam Leffler 713de47c390SBjoern A. Zeeb /* Set default. */ 71488768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 71588768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; 71688768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; 71788768458SSam Leffler 71888768458SSam Leffler nxt = -1; 71988768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 72088768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 72188768458SSam Leffler return; 72288768458SSam Leffler 72388768458SSam Leffler switch (nxt) { 72488768458SSam Leffler case IPPROTO_TCP: 72588768458SSam Leffler spidx->ul_proto = nxt; 72688768458SSam Leffler if (!needport) 72788768458SSam Leffler break; 72888768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 72988768458SSam Leffler break; 73088768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 73188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; 73288768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; 73388768458SSam Leffler break; 73488768458SSam Leffler case IPPROTO_UDP: 73588768458SSam Leffler spidx->ul_proto = nxt; 73688768458SSam Leffler if (!needport) 73788768458SSam Leffler break; 73888768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 73988768458SSam Leffler break; 74088768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 74188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; 74288768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; 74388768458SSam Leffler break; 74488768458SSam Leffler case IPPROTO_ICMPV6: 7450e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 7460e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 7470e3c2be4SBjoern A. Zeeb break; 7480e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 7490e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->src)->sin6_port = 7500e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_type); 7510e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = 7520e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_code); 7530e3c2be4SBjoern A. Zeeb break; 75488768458SSam Leffler default: 755de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 75688768458SSam Leffler spidx->ul_proto = nxt; 75788768458SSam Leffler break; 75888768458SSam Leffler } 75988768458SSam Leffler } 76088768458SSam Leffler 761de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 76288768458SSam Leffler static int 763cd1a38f5SBjoern A. Zeeb ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 76488768458SSam Leffler { 76588768458SSam Leffler struct ip6_hdr *ip6 = NULL; 76688768458SSam Leffler struct ip6_hdr ip6buf; 76788768458SSam Leffler struct sockaddr_in6 *sin6; 76888768458SSam Leffler 76988768458SSam Leffler if (m->m_len >= sizeof(*ip6)) 77088768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 77188768458SSam Leffler else { 77288768458SSam Leffler m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 77388768458SSam Leffler ip6 = &ip6buf; 77488768458SSam Leffler } 77588768458SSam Leffler 77688768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->src; 77788768458SSam Leffler bzero(sin6, sizeof(*sin6)); 77888768458SSam Leffler sin6->sin6_family = AF_INET6; 77988768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 78088768458SSam Leffler bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); 78188768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 78288768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 78388768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); 78488768458SSam Leffler } 78588768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 78688768458SSam Leffler 78788768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->dst; 78888768458SSam Leffler bzero(sin6, sizeof(*sin6)); 78988768458SSam Leffler sin6->sin6_family = AF_INET6; 79088768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 79188768458SSam Leffler bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); 79288768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 79388768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 79488768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); 79588768458SSam Leffler } 79688768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 79788768458SSam Leffler 798de47c390SBjoern A. Zeeb return (0); 79988768458SSam Leffler } 80088768458SSam Leffler #endif 80188768458SSam Leffler 80288768458SSam Leffler static void 803cd1a38f5SBjoern A. Zeeb ipsec_delpcbpolicy(struct inpcbpolicy *p) 80488768458SSam Leffler { 805de47c390SBjoern A. Zeeb 8066464079fSSam Leffler free(p, M_IPSEC_INPCB); 80788768458SSam Leffler } 80888768458SSam Leffler 809de47c390SBjoern A. Zeeb /* Initialize policy in PCB. */ 81088768458SSam Leffler int 811cd1a38f5SBjoern A. Zeeb ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) 81288768458SSam Leffler { 81388768458SSam Leffler struct inpcbpolicy *new; 81488768458SSam Leffler 815de47c390SBjoern A. Zeeb /* Sanity check. */ 81688768458SSam Leffler if (so == NULL || pcb_sp == NULL) 8179ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 81888768458SSam Leffler 81988768458SSam Leffler new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), 8206464079fSSam Leffler M_IPSEC_INPCB, M_NOWAIT|M_ZERO); 82188768458SSam Leffler if (new == NULL) { 8229ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 823de47c390SBjoern A. Zeeb return (ENOBUFS); 82488768458SSam Leffler } 82588768458SSam Leffler 8269ffa9677SSam Leffler new->priv = IPSEC_IS_PRIVILEGED_SO(so); 82788768458SSam Leffler 82888768458SSam Leffler if ((new->sp_in = KEY_NEWSP()) == NULL) { 82988768458SSam Leffler ipsec_delpcbpolicy(new); 830de47c390SBjoern A. Zeeb return (ENOBUFS); 83188768458SSam Leffler } 83288768458SSam Leffler new->sp_in->policy = IPSEC_POLICY_ENTRUST; 83388768458SSam Leffler if ((new->sp_out = KEY_NEWSP()) == NULL) { 83488768458SSam Leffler KEY_FREESP(&new->sp_in); 83588768458SSam Leffler ipsec_delpcbpolicy(new); 836de47c390SBjoern A. Zeeb return (ENOBUFS); 83788768458SSam Leffler } 83888768458SSam Leffler new->sp_out->policy = IPSEC_POLICY_ENTRUST; 83988768458SSam Leffler *pcb_sp = new; 84088768458SSam Leffler 841de47c390SBjoern A. Zeeb return (0); 84288768458SSam Leffler } 84388768458SSam Leffler 844de47c390SBjoern A. Zeeb /* Copy old IPsec policy into new. */ 84588768458SSam Leffler int 846cd1a38f5SBjoern A. Zeeb ipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new) 84788768458SSam Leffler { 84888768458SSam Leffler struct secpolicy *sp; 84988768458SSam Leffler 85088768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_in); 85188768458SSam Leffler if (sp) { 85288768458SSam Leffler KEY_FREESP(&new->sp_in); 85388768458SSam Leffler new->sp_in = sp; 85488768458SSam Leffler } else 855de47c390SBjoern A. Zeeb return (ENOBUFS); 85688768458SSam Leffler 85788768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_out); 85888768458SSam Leffler if (sp) { 85988768458SSam Leffler KEY_FREESP(&new->sp_out); 86088768458SSam Leffler new->sp_out = sp; 86188768458SSam Leffler } else 862de47c390SBjoern A. Zeeb return (ENOBUFS); 86388768458SSam Leffler 86488768458SSam Leffler new->priv = old->priv; 86588768458SSam Leffler 866de47c390SBjoern A. Zeeb return (0); 86788768458SSam Leffler } 86888768458SSam Leffler 8696464079fSSam Leffler struct ipsecrequest * 8706464079fSSam Leffler ipsec_newisr(void) 8716464079fSSam Leffler { 8726464079fSSam Leffler struct ipsecrequest *p; 8736464079fSSam Leffler 8746464079fSSam Leffler p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); 8756464079fSSam Leffler if (p != NULL) 8769ffa9677SSam Leffler IPSECREQUEST_LOCK_INIT(p); 877de47c390SBjoern A. Zeeb return (p); 8786464079fSSam Leffler } 8796464079fSSam Leffler 8806464079fSSam Leffler void 8816464079fSSam Leffler ipsec_delisr(struct ipsecrequest *p) 8826464079fSSam Leffler { 883de47c390SBjoern A. Zeeb 8849ffa9677SSam Leffler IPSECREQUEST_LOCK_DESTROY(p); 8856464079fSSam Leffler free(p, M_IPSEC_SR); 8866464079fSSam Leffler } 8876464079fSSam Leffler 888de47c390SBjoern A. Zeeb /* Deep-copy a policy in PCB. */ 88988768458SSam Leffler static struct secpolicy * 890cd1a38f5SBjoern A. Zeeb ipsec_deepcopy_policy(struct secpolicy *src) 89188768458SSam Leffler { 89288768458SSam Leffler struct ipsecrequest *newchain = NULL; 89388768458SSam Leffler struct ipsecrequest *p; 89488768458SSam Leffler struct ipsecrequest **q; 89588768458SSam Leffler struct ipsecrequest *r; 89688768458SSam Leffler struct secpolicy *dst; 89788768458SSam Leffler 89888768458SSam Leffler if (src == NULL) 899de47c390SBjoern A. Zeeb return (NULL); 90088768458SSam Leffler dst = KEY_NEWSP(); 90188768458SSam Leffler if (dst == NULL) 902de47c390SBjoern A. Zeeb return (NULL); 90388768458SSam Leffler 90488768458SSam Leffler /* 905de47c390SBjoern A. Zeeb * Deep-copy IPsec request chain. This is required since struct 90688768458SSam Leffler * ipsecrequest is not reference counted. 90788768458SSam Leffler */ 90888768458SSam Leffler q = &newchain; 90988768458SSam Leffler for (p = src->req; p; p = p->next) { 9106464079fSSam Leffler *q = ipsec_newisr(); 91188768458SSam Leffler if (*q == NULL) 91288768458SSam Leffler goto fail; 91388768458SSam Leffler (*q)->saidx.proto = p->saidx.proto; 91488768458SSam Leffler (*q)->saidx.mode = p->saidx.mode; 91588768458SSam Leffler (*q)->level = p->level; 91688768458SSam Leffler (*q)->saidx.reqid = p->saidx.reqid; 91788768458SSam Leffler 91888768458SSam Leffler bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); 91988768458SSam Leffler bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); 92088768458SSam Leffler 92188768458SSam Leffler (*q)->sp = dst; 92288768458SSam Leffler 92388768458SSam Leffler q = &((*q)->next); 92488768458SSam Leffler } 92588768458SSam Leffler 92688768458SSam Leffler dst->req = newchain; 92788768458SSam Leffler dst->policy = src->policy; 928de47c390SBjoern A. Zeeb /* Do not touch the refcnt fields. */ 92988768458SSam Leffler 930de47c390SBjoern A. Zeeb return (dst); 93188768458SSam Leffler 93288768458SSam Leffler fail: 93388768458SSam Leffler for (p = newchain; p; p = r) { 93488768458SSam Leffler r = p->next; 9356464079fSSam Leffler ipsec_delisr(p); 93688768458SSam Leffler p = NULL; 93788768458SSam Leffler } 938de47c390SBjoern A. Zeeb return (NULL); 93988768458SSam Leffler } 94088768458SSam Leffler 941de47c390SBjoern A. Zeeb /* Set policy and IPsec request if present. */ 94288768458SSam Leffler static int 94397aa4a51SBjoern A. Zeeb ipsec_set_policy_internal(struct secpolicy **pcb_sp, int optname, 94497aa4a51SBjoern A. Zeeb caddr_t request, size_t len, struct ucred *cred) 94588768458SSam Leffler { 94688768458SSam Leffler struct sadb_x_policy *xpl; 94788768458SSam Leffler struct secpolicy *newsp = NULL; 94888768458SSam Leffler int error; 94988768458SSam Leffler 950de47c390SBjoern A. Zeeb /* Sanity check. */ 95188768458SSam Leffler if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) 952de47c390SBjoern A. Zeeb return (EINVAL); 95388768458SSam Leffler if (len < sizeof(*xpl)) 954de47c390SBjoern A. Zeeb return (EINVAL); 95588768458SSam Leffler xpl = (struct sadb_x_policy *)request; 95688768458SSam Leffler 95788768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 9589ffa9677SSam Leffler printf("%s: passed policy\n", __func__); 95988768458SSam Leffler kdebug_sadb_x_policy((struct sadb_ext *)xpl)); 96088768458SSam Leffler 961de47c390SBjoern A. Zeeb /* Check policy type. */ 96297aa4a51SBjoern A. Zeeb /* ipsec_set_policy_internal() accepts IPSEC, ENTRUST and BYPASS. */ 96388768458SSam Leffler if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD 96488768458SSam Leffler || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) 965de47c390SBjoern A. Zeeb return (EINVAL); 96688768458SSam Leffler 967de47c390SBjoern A. Zeeb /* Check privileged socket. */ 968c26fe973SBjoern A. Zeeb if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { 969c26fe973SBjoern A. Zeeb error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); 970c26fe973SBjoern A. Zeeb if (error) 971de47c390SBjoern A. Zeeb return (EACCES); 972c26fe973SBjoern A. Zeeb } 97388768458SSam Leffler 974de47c390SBjoern A. Zeeb /* Allocating new SP entry. */ 97588768458SSam Leffler if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) 976de47c390SBjoern A. Zeeb return (error); 97788768458SSam Leffler 978de47c390SBjoern A. Zeeb /* Clear old SP and set new SP. */ 97988768458SSam Leffler KEY_FREESP(pcb_sp); 98088768458SSam Leffler *pcb_sp = newsp; 98188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 9829ffa9677SSam Leffler printf("%s: new policy\n", __func__); 98388768458SSam Leffler kdebug_secpolicy(newsp)); 98488768458SSam Leffler 985de47c390SBjoern A. Zeeb return (0); 98688768458SSam Leffler } 98788768458SSam Leffler 98888768458SSam Leffler int 98997aa4a51SBjoern A. Zeeb ipsec_set_policy(struct inpcb *inp, int optname, caddr_t request, 990cd1a38f5SBjoern A. Zeeb size_t len, struct ucred *cred) 99188768458SSam Leffler { 99288768458SSam Leffler struct sadb_x_policy *xpl; 99388768458SSam Leffler struct secpolicy **pcb_sp; 99488768458SSam Leffler 995de47c390SBjoern A. Zeeb /* Sanity check. */ 99688768458SSam Leffler if (inp == NULL || request == NULL) 997de47c390SBjoern A. Zeeb return (EINVAL); 99888768458SSam Leffler if (len < sizeof(*xpl)) 999de47c390SBjoern A. Zeeb return (EINVAL); 100088768458SSam Leffler xpl = (struct sadb_x_policy *)request; 100188768458SSam Leffler 1002de47c390SBjoern A. Zeeb /* Select direction. */ 100388768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 100488768458SSam Leffler case IPSEC_DIR_INBOUND: 100588768458SSam Leffler pcb_sp = &inp->inp_sp->sp_in; 100688768458SSam Leffler break; 100788768458SSam Leffler case IPSEC_DIR_OUTBOUND: 100888768458SSam Leffler pcb_sp = &inp->inp_sp->sp_out; 100988768458SSam Leffler break; 101088768458SSam Leffler default: 10119ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 101288768458SSam Leffler xpl->sadb_x_policy_dir)); 1013de47c390SBjoern A. Zeeb return (EINVAL); 101488768458SSam Leffler } 101588768458SSam Leffler 101697aa4a51SBjoern A. Zeeb return (ipsec_set_policy_internal(pcb_sp, optname, request, len, cred)); 101788768458SSam Leffler } 101888768458SSam Leffler 101988768458SSam Leffler int 102097aa4a51SBjoern A. Zeeb ipsec_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1021cd1a38f5SBjoern A. Zeeb struct mbuf **mp) 102288768458SSam Leffler { 102388768458SSam Leffler struct sadb_x_policy *xpl; 102488768458SSam Leffler struct secpolicy *pcb_sp; 102588768458SSam Leffler 1026de47c390SBjoern A. Zeeb /* Sanity check. */ 102788768458SSam Leffler if (inp == NULL || request == NULL || mp == NULL) 1028de47c390SBjoern A. Zeeb return (EINVAL); 10299ffa9677SSam Leffler IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 103088768458SSam Leffler if (len < sizeof(*xpl)) 1031de47c390SBjoern A. Zeeb return (EINVAL); 103288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 103388768458SSam Leffler 1034de47c390SBjoern A. Zeeb /* Select direction. */ 103588768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 103688768458SSam Leffler case IPSEC_DIR_INBOUND: 103788768458SSam Leffler pcb_sp = inp->inp_sp->sp_in; 103888768458SSam Leffler break; 103988768458SSam Leffler case IPSEC_DIR_OUTBOUND: 104088768458SSam Leffler pcb_sp = inp->inp_sp->sp_out; 104188768458SSam Leffler break; 104288768458SSam Leffler default: 10439ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 104488768458SSam Leffler xpl->sadb_x_policy_dir)); 1045de47c390SBjoern A. Zeeb return (EINVAL); 104688768458SSam Leffler } 104788768458SSam Leffler 104897aa4a51SBjoern A. Zeeb /* Sanity check. Should be an IPSEC_ASSERT. */ 104997aa4a51SBjoern A. Zeeb if (pcb_sp == NULL) 105097aa4a51SBjoern A. Zeeb return (EINVAL); 105197aa4a51SBjoern A. Zeeb 105297aa4a51SBjoern A. Zeeb *mp = key_sp2msg(pcb_sp); 105397aa4a51SBjoern A. Zeeb if (!*mp) { 105497aa4a51SBjoern A. Zeeb ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 105597aa4a51SBjoern A. Zeeb return (ENOBUFS); 105697aa4a51SBjoern A. Zeeb } 105797aa4a51SBjoern A. Zeeb 105897aa4a51SBjoern A. Zeeb (*mp)->m_type = MT_DATA; 105997aa4a51SBjoern A. Zeeb KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 106097aa4a51SBjoern A. Zeeb printf("%s:\n", __func__); kdebug_mbuf(*mp)); 106197aa4a51SBjoern A. Zeeb 106297aa4a51SBjoern A. Zeeb return (0); 106388768458SSam Leffler } 106488768458SSam Leffler 1065de47c390SBjoern A. Zeeb /* Delete policy in PCB. */ 106688768458SSam Leffler int 1067cd1a38f5SBjoern A. Zeeb ipsec_delete_pcbpolicy(struct inpcb *inp) 106888768458SSam Leffler { 10699ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inp")); 107088768458SSam Leffler 107188768458SSam Leffler if (inp->inp_sp == NULL) 1072de47c390SBjoern A. Zeeb return (0); 107388768458SSam Leffler 107488768458SSam Leffler if (inp->inp_sp->sp_in != NULL) 107588768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_in); 107688768458SSam Leffler 107788768458SSam Leffler if (inp->inp_sp->sp_out != NULL) 107888768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_out); 107988768458SSam Leffler 108088768458SSam Leffler ipsec_delpcbpolicy(inp->inp_sp); 108188768458SSam Leffler inp->inp_sp = NULL; 108288768458SSam Leffler 1083de47c390SBjoern A. Zeeb return (0); 108488768458SSam Leffler } 108588768458SSam Leffler 108688768458SSam Leffler /* 1087de47c390SBjoern A. Zeeb * Return current level. 108888768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 108988768458SSam Leffler */ 109088768458SSam Leffler u_int 1091cd1a38f5SBjoern A. Zeeb ipsec_get_reqlevel(struct ipsecrequest *isr) 109288768458SSam Leffler { 109388768458SSam Leffler u_int level = 0; 109488768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 109588768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 109688768458SSam Leffler 10979ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); 10989ffa9677SSam Leffler IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, 10999ffa9677SSam Leffler ("af family mismatch, src %u, dst %u", 110088768458SSam Leffler isr->sp->spidx.src.sa.sa_family, 110188768458SSam Leffler isr->sp->spidx.dst.sa.sa_family)); 110288768458SSam Leffler 1103de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */ 110488768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 110588768458SSam Leffler (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ 110688768458SSam Leffler && (lev) != IPSEC_LEVEL_UNIQUE) \ 1107603724d3SBjoern A. Zeeb ? (V_ipsec_debug \ 110888768458SSam Leffler ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 110988768458SSam Leffler (lev), IPSEC_LEVEL_REQUIRE) \ 111088768458SSam Leffler : 0), \ 111188768458SSam Leffler (lev) = IPSEC_LEVEL_REQUIRE, \ 111288768458SSam Leffler (lev) \ 111388768458SSam Leffler : (lev)) 111488768458SSam Leffler 1115de47c390SBjoern A. Zeeb /* Set default level. */ 111688768458SSam Leffler switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { 111788768458SSam Leffler #ifdef INET 111888768458SSam Leffler case AF_INET: 1119603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 1120603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 1121603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 1122603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 112388768458SSam Leffler break; 112488768458SSam Leffler #endif 112588768458SSam Leffler #ifdef INET6 112688768458SSam Leffler case AF_INET6: 1127603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 1128603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 1129603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 1130603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 113188768458SSam Leffler break; 113288768458SSam Leffler #endif /* INET6 */ 113388768458SSam Leffler default: 11349ffa9677SSam Leffler panic("%s: unknown af %u", 11359ffa9677SSam Leffler __func__, isr->sp->spidx.src.sa.sa_family); 113688768458SSam Leffler } 113788768458SSam Leffler 113888768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 113988768458SSam Leffler 1140de47c390SBjoern A. Zeeb /* Set level. */ 114188768458SSam Leffler switch (isr->level) { 114288768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 114388768458SSam Leffler switch (isr->saidx.proto) { 114488768458SSam Leffler case IPPROTO_ESP: 114588768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 114688768458SSam Leffler level = esp_net_deflev; 114788768458SSam Leffler else 114888768458SSam Leffler level = esp_trans_deflev; 114988768458SSam Leffler break; 115088768458SSam Leffler case IPPROTO_AH: 115188768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 115288768458SSam Leffler level = ah_net_deflev; 115388768458SSam Leffler else 115488768458SSam Leffler level = ah_trans_deflev; 11558381996eSSam Leffler break; 115688768458SSam Leffler case IPPROTO_IPCOMP: 115788768458SSam Leffler /* 1158de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document says that 1159de47c390SBjoern A. Zeeb * we shouldn't compress small packets. 116088768458SSam Leffler */ 116188768458SSam Leffler level = IPSEC_LEVEL_USE; 116288768458SSam Leffler break; 116388768458SSam Leffler default: 11649ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 116588768458SSam Leffler isr->saidx.proto); 116688768458SSam Leffler } 116788768458SSam Leffler break; 116888768458SSam Leffler 116988768458SSam Leffler case IPSEC_LEVEL_USE: 117088768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 117188768458SSam Leffler level = isr->level; 117288768458SSam Leffler break; 117388768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 117488768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 117588768458SSam Leffler break; 117688768458SSam Leffler 117788768458SSam Leffler default: 11789ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 117988768458SSam Leffler } 118088768458SSam Leffler 1181de47c390SBjoern A. Zeeb return (level); 118288768458SSam Leffler } 118388768458SSam Leffler 118488768458SSam Leffler /* 118588768458SSam Leffler * Check security policy requirements against the actual 118688768458SSam Leffler * packet contents. Return one if the packet should be 118788768458SSam Leffler * reject as "invalid"; otherwiser return zero to have the 118888768458SSam Leffler * packet treated as "valid". 118988768458SSam Leffler * 119088768458SSam Leffler * OUT: 119188768458SSam Leffler * 0: valid 119288768458SSam Leffler * 1: invalid 119388768458SSam Leffler */ 119488768458SSam Leffler int 119588768458SSam Leffler ipsec_in_reject(struct secpolicy *sp, struct mbuf *m) 119688768458SSam Leffler { 119788768458SSam Leffler struct ipsecrequest *isr; 119888768458SSam Leffler int need_auth; 119988768458SSam Leffler 120088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 12019ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 120288768458SSam Leffler 1203de47c390SBjoern A. Zeeb /* Check policy. */ 120488768458SSam Leffler switch (sp->policy) { 120588768458SSam Leffler case IPSEC_POLICY_DISCARD: 1206de47c390SBjoern A. Zeeb return (1); 120788768458SSam Leffler case IPSEC_POLICY_BYPASS: 120888768458SSam Leffler case IPSEC_POLICY_NONE: 1209de47c390SBjoern A. Zeeb return (0); 121088768458SSam Leffler } 121188768458SSam Leffler 12129ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 12139ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 121488768458SSam Leffler 1215de47c390SBjoern A. Zeeb /* XXX Should compare policy against IPsec header history. */ 121688768458SSam Leffler 121788768458SSam Leffler need_auth = 0; 121888768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 121988768458SSam Leffler if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) 122088768458SSam Leffler continue; 122188768458SSam Leffler switch (isr->saidx.proto) { 122288768458SSam Leffler case IPPROTO_ESP: 122388768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 122488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12259ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 122688768458SSam Leffler m->m_flags)); 1227de47c390SBjoern A. Zeeb return (1); 122888768458SSam Leffler } 122988768458SSam Leffler 123088768458SSam Leffler if (!need_auth && 123188768458SSam Leffler isr->sav != NULL && 123288768458SSam Leffler isr->sav->tdb_authalgxform != NULL && 123388768458SSam Leffler (m->m_flags & M_AUTHIPDGM) == 0) { 123488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12359ffa9677SSam Leffler printf("%s: ESP/AH m_flags:%x\n", __func__, 123688768458SSam Leffler m->m_flags)); 1237de47c390SBjoern A. Zeeb return (1); 123888768458SSam Leffler } 123988768458SSam Leffler break; 124088768458SSam Leffler case IPPROTO_AH: 124188768458SSam Leffler need_auth = 1; 124288768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 124388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 12449ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 124588768458SSam Leffler m->m_flags)); 1246de47c390SBjoern A. Zeeb return (1); 124788768458SSam Leffler } 124888768458SSam Leffler break; 124988768458SSam Leffler case IPPROTO_IPCOMP: 125088768458SSam Leffler /* 1251de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document 125288768458SSam Leffler * says that we shouldn't compress small 1253de47c390SBjoern A. Zeeb * packets. IPComp policy should always be 125488768458SSam Leffler * treated as being in "use" level. 125588768458SSam Leffler */ 125688768458SSam Leffler break; 125788768458SSam Leffler } 125888768458SSam Leffler } 1259de47c390SBjoern A. Zeeb return (0); /* Valid. */ 126088768458SSam Leffler } 126188768458SSam Leffler 1262a91150daSAndrey V. Elsukov /* 1263a91150daSAndrey V. Elsukov * Non zero return value means security policy DISCARD or policy violation. 1264a91150daSAndrey V. Elsukov */ 126597aa4a51SBjoern A. Zeeb static int 126697aa4a51SBjoern A. Zeeb ipsec46_in_reject(struct mbuf *m, struct inpcb *inp) 126788768458SSam Leffler { 126888768458SSam Leffler struct secpolicy *sp; 126988768458SSam Leffler int error; 127088768458SSam Leffler int result; 127188768458SSam Leffler 12729ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 127388768458SSam Leffler 12740275b2e3SAndrey V. Elsukov /* Get SP for this packet. */ 127588768458SSam Leffler if (inp == NULL) 12760275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, &error); 127788768458SSam Leffler else 127888768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 127988768458SSam Leffler 128088768458SSam Leffler if (sp != NULL) { 128188768458SSam Leffler result = ipsec_in_reject(sp, m); 128288768458SSam Leffler KEY_FREESP(&sp); 128388768458SSam Leffler } else { 1284a91150daSAndrey V. Elsukov result = 1; /* treat errors as policy violation */ 128588768458SSam Leffler } 1286de47c390SBjoern A. Zeeb return (result); 128788768458SSam Leffler } 128888768458SSam Leffler 128997aa4a51SBjoern A. Zeeb /* 129097aa4a51SBjoern A. Zeeb * Check AH/ESP integrity. 129197aa4a51SBjoern A. Zeeb * This function is called from tcp_input(), udp_input(), 129297aa4a51SBjoern A. Zeeb * and {ah,esp}4_input for tunnel mode. 129397aa4a51SBjoern A. Zeeb */ 129497aa4a51SBjoern A. Zeeb int 129597aa4a51SBjoern A. Zeeb ipsec4_in_reject(struct mbuf *m, struct inpcb *inp) 129697aa4a51SBjoern A. Zeeb { 129797aa4a51SBjoern A. Zeeb int result; 129897aa4a51SBjoern A. Zeeb 129997aa4a51SBjoern A. Zeeb result = ipsec46_in_reject(m, inp); 130097aa4a51SBjoern A. Zeeb if (result) 13016659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_in_polvio); 130297aa4a51SBjoern A. Zeeb 130397aa4a51SBjoern A. Zeeb return (result); 130497aa4a51SBjoern A. Zeeb } 130597aa4a51SBjoern A. Zeeb 130688768458SSam Leffler #ifdef INET6 130788768458SSam Leffler /* 130888768458SSam Leffler * Check AH/ESP integrity. 130988768458SSam Leffler * This function is called from tcp6_input(), udp6_input(), 1310de47c390SBjoern A. Zeeb * and {ah,esp}6_input for tunnel mode. 131188768458SSam Leffler */ 131288768458SSam Leffler int 1313cd1a38f5SBjoern A. Zeeb ipsec6_in_reject(struct mbuf *m, struct inpcb *inp) 131488768458SSam Leffler { 131588768458SSam Leffler int result; 131688768458SSam Leffler 131797aa4a51SBjoern A. Zeeb result = ipsec46_in_reject(m, inp); 131888768458SSam Leffler if (result) 13196659296cSAndrey V. Elsukov IPSEC6STAT_INC(ips_in_polvio); 132097aa4a51SBjoern A. Zeeb 1321de47c390SBjoern A. Zeeb return (result); 132288768458SSam Leffler } 132388768458SSam Leffler #endif 132488768458SSam Leffler 132588768458SSam Leffler /* 1326de47c390SBjoern A. Zeeb * Compute the byte size to be occupied by IPsec header. 1327de47c390SBjoern A. Zeeb * In case it is tunnelled, it includes the size of outer IP header. 1328de47c390SBjoern A. Zeeb * NOTE: SP passed is freed in this function. 132988768458SSam Leffler */ 133088768458SSam Leffler static size_t 133197aa4a51SBjoern A. Zeeb ipsec_hdrsiz_internal(struct secpolicy *sp) 133288768458SSam Leffler { 133388768458SSam Leffler struct ipsecrequest *isr; 13341f8bd75eSBjoern A. Zeeb size_t size; 133588768458SSam Leffler 133688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 13379ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 133888768458SSam Leffler 133988768458SSam Leffler switch (sp->policy) { 134088768458SSam Leffler case IPSEC_POLICY_DISCARD: 134188768458SSam Leffler case IPSEC_POLICY_BYPASS: 134288768458SSam Leffler case IPSEC_POLICY_NONE: 1343de47c390SBjoern A. Zeeb return (0); 134488768458SSam Leffler } 134588768458SSam Leffler 13469ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 13479ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 134888768458SSam Leffler 13491f8bd75eSBjoern A. Zeeb size = 0; 135088768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 135188768458SSam Leffler size_t clen = 0; 135288768458SSam Leffler 135388768458SSam Leffler switch (isr->saidx.proto) { 135488768458SSam Leffler case IPPROTO_ESP: 135588768458SSam Leffler clen = esp_hdrsiz(isr->sav); 135688768458SSam Leffler break; 135788768458SSam Leffler case IPPROTO_AH: 135888768458SSam Leffler clen = ah_hdrsiz(isr->sav); 135988768458SSam Leffler break; 136088768458SSam Leffler case IPPROTO_IPCOMP: 136188768458SSam Leffler clen = sizeof(struct ipcomp); 136288768458SSam Leffler break; 136388768458SSam Leffler } 136488768458SSam Leffler 136588768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 136688768458SSam Leffler switch (isr->saidx.dst.sa.sa_family) { 136788768458SSam Leffler case AF_INET: 136888768458SSam Leffler clen += sizeof(struct ip); 136988768458SSam Leffler break; 137088768458SSam Leffler #ifdef INET6 137188768458SSam Leffler case AF_INET6: 137288768458SSam Leffler clen += sizeof(struct ip6_hdr); 137388768458SSam Leffler break; 137488768458SSam Leffler #endif 137588768458SSam Leffler default: 13769ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 13779ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 137888768458SSam Leffler ((struct sockaddr *)&isr->saidx.dst)->sa_family)); 137988768458SSam Leffler break; 138088768458SSam Leffler } 138188768458SSam Leffler } 13821f8bd75eSBjoern A. Zeeb size += clen; 138388768458SSam Leffler } 138488768458SSam Leffler 13851f8bd75eSBjoern A. Zeeb return (size); 138688768458SSam Leffler } 138788768458SSam Leffler 138897aa4a51SBjoern A. Zeeb /* 138997aa4a51SBjoern A. Zeeb * This function is called from ipsec_hdrsiz_tcp(), ip_ipsec_mtu(), 139097aa4a51SBjoern A. Zeeb * disabled ip6_ipsec_mtu() and ip6_forward(). 139197aa4a51SBjoern A. Zeeb */ 139288768458SSam Leffler size_t 139397aa4a51SBjoern A. Zeeb ipsec_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) 139488768458SSam Leffler { 139588768458SSam Leffler struct secpolicy *sp; 139688768458SSam Leffler int error; 139788768458SSam Leffler size_t size; 139888768458SSam Leffler 13999ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 140088768458SSam Leffler 14010275b2e3SAndrey V. Elsukov /* Get SP for this packet. */ 140288768458SSam Leffler if (inp == NULL) 14030275b2e3SAndrey V. Elsukov sp = ipsec_getpolicybyaddr(m, dir, &error); 140488768458SSam Leffler else 140588768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, &error); 140688768458SSam Leffler 140788768458SSam Leffler if (sp != NULL) { 140897aa4a51SBjoern A. Zeeb size = ipsec_hdrsiz_internal(sp); 140988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 14109ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, 141188768458SSam Leffler (unsigned long)size)); 141288768458SSam Leffler 141388768458SSam Leffler KEY_FREESP(&sp); 141488768458SSam Leffler } else { 1415de47c390SBjoern A. Zeeb size = 0; /* XXX Should be panic? 14164a67e051SBjoern A. Zeeb * -> No, we are called w/o knowing if 14174a67e051SBjoern A. Zeeb * IPsec processing is needed. */ 141888768458SSam Leffler } 1419de47c390SBjoern A. Zeeb return (size); 142088768458SSam Leffler } 142188768458SSam Leffler 142288768458SSam Leffler /* 142388768458SSam Leffler * Check the variable replay window. 142488768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 142588768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 142688768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 142788768458SSam Leffler * beforehand). 142888768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 142988768458SSam Leffler * 1430de47c390SBjoern A. Zeeb * Based on RFC 2401. 143188768458SSam Leffler */ 143288768458SSam Leffler int 1433cd1a38f5SBjoern A. Zeeb ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) 143488768458SSam Leffler { 143588768458SSam Leffler const struct secreplay *replay; 143688768458SSam Leffler u_int32_t diff; 143788768458SSam Leffler int fr; 1438de47c390SBjoern A. Zeeb u_int32_t wsizeb; /* Constant: bits of window size. */ 1439de47c390SBjoern A. Zeeb int frlast; /* Constant: last frame. */ 144088768458SSam Leffler 14419ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 14429ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 144388768458SSam Leffler 144488768458SSam Leffler replay = sav->replay; 144588768458SSam Leffler 144688768458SSam Leffler if (replay->wsize == 0) 1447de47c390SBjoern A. Zeeb return (1); /* No need to check replay. */ 144888768458SSam Leffler 1449de47c390SBjoern A. Zeeb /* Constant. */ 145088768458SSam Leffler frlast = replay->wsize - 1; 145188768458SSam Leffler wsizeb = replay->wsize << 3; 145288768458SSam Leffler 1453de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 145488768458SSam Leffler if (seq == 0) 1455de47c390SBjoern A. Zeeb return (0); 145688768458SSam Leffler 1457de47c390SBjoern A. Zeeb /* First time is always okay. */ 145888768458SSam Leffler if (replay->count == 0) 1459de47c390SBjoern A. Zeeb return (1); 146088768458SSam Leffler 146188768458SSam Leffler if (seq > replay->lastseq) { 1462de47c390SBjoern A. Zeeb /* Larger sequences are okay. */ 1463de47c390SBjoern A. Zeeb return (1); 146488768458SSam Leffler } else { 146588768458SSam Leffler /* seq is equal or less than lastseq. */ 146688768458SSam Leffler diff = replay->lastseq - seq; 146788768458SSam Leffler 1468de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 146988768458SSam Leffler if (diff >= wsizeb) 1470de47c390SBjoern A. Zeeb return (0); 147188768458SSam Leffler 147288768458SSam Leffler fr = frlast - diff / 8; 147388768458SSam Leffler 1474de47c390SBjoern A. Zeeb /* This packet already seen? */ 147588768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1476de47c390SBjoern A. Zeeb return (0); 147788768458SSam Leffler 1478de47c390SBjoern A. Zeeb /* Out of order but good. */ 1479de47c390SBjoern A. Zeeb return (1); 148088768458SSam Leffler } 148188768458SSam Leffler } 148288768458SSam Leffler 148388768458SSam Leffler /* 1484de47c390SBjoern A. Zeeb * Check replay counter whether to update or not. 148588768458SSam Leffler * OUT: 0: OK 148688768458SSam Leffler * 1: NG 148788768458SSam Leffler */ 148888768458SSam Leffler int 1489cd1a38f5SBjoern A. Zeeb ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) 149088768458SSam Leffler { 149188768458SSam Leffler struct secreplay *replay; 149288768458SSam Leffler u_int32_t diff; 149388768458SSam Leffler int fr; 1494de47c390SBjoern A. Zeeb u_int32_t wsizeb; /* Constant: bits of window size. */ 1495de47c390SBjoern A. Zeeb int frlast; /* Constant: last frame. */ 149688768458SSam Leffler 14979ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 14989ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 149988768458SSam Leffler 150088768458SSam Leffler replay = sav->replay; 150188768458SSam Leffler 150288768458SSam Leffler if (replay->wsize == 0) 1503de47c390SBjoern A. Zeeb goto ok; /* No need to check replay. */ 150488768458SSam Leffler 1505de47c390SBjoern A. Zeeb /* Constant. */ 150688768458SSam Leffler frlast = replay->wsize - 1; 150788768458SSam Leffler wsizeb = replay->wsize << 3; 150888768458SSam Leffler 1509de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 151088768458SSam Leffler if (seq == 0) 1511de47c390SBjoern A. Zeeb return (1); 151288768458SSam Leffler 1513de47c390SBjoern A. Zeeb /* First time. */ 151488768458SSam Leffler if (replay->count == 0) { 151588768458SSam Leffler replay->lastseq = seq; 151688768458SSam Leffler bzero(replay->bitmap, replay->wsize); 151788768458SSam Leffler (replay->bitmap)[frlast] = 1; 151888768458SSam Leffler goto ok; 151988768458SSam Leffler } 152088768458SSam Leffler 152188768458SSam Leffler if (seq > replay->lastseq) { 152288768458SSam Leffler /* seq is larger than lastseq. */ 152388768458SSam Leffler diff = seq - replay->lastseq; 152488768458SSam Leffler 1525de47c390SBjoern A. Zeeb /* New larger sequence number. */ 152688768458SSam Leffler if (diff < wsizeb) { 1527de47c390SBjoern A. Zeeb /* In window. */ 1528de47c390SBjoern A. Zeeb /* Set bit for this packet. */ 152988768458SSam Leffler vshiftl(replay->bitmap, diff, replay->wsize); 153088768458SSam Leffler (replay->bitmap)[frlast] |= 1; 153188768458SSam Leffler } else { 1532de47c390SBjoern A. Zeeb /* This packet has a "way larger". */ 153388768458SSam Leffler bzero(replay->bitmap, replay->wsize); 153488768458SSam Leffler (replay->bitmap)[frlast] = 1; 153588768458SSam Leffler } 153688768458SSam Leffler replay->lastseq = seq; 153788768458SSam Leffler 1538de47c390SBjoern A. Zeeb /* Larger is good. */ 153988768458SSam Leffler } else { 154088768458SSam Leffler /* seq is equal or less than lastseq. */ 154188768458SSam Leffler diff = replay->lastseq - seq; 154288768458SSam Leffler 1543de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 154488768458SSam Leffler if (diff >= wsizeb) 1545de47c390SBjoern A. Zeeb return (1); 154688768458SSam Leffler 154788768458SSam Leffler fr = frlast - diff / 8; 154888768458SSam Leffler 1549de47c390SBjoern A. Zeeb /* This packet already seen? */ 155088768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1551de47c390SBjoern A. Zeeb return (1); 155288768458SSam Leffler 1553de47c390SBjoern A. Zeeb /* Mark as seen. */ 155488768458SSam Leffler (replay->bitmap)[fr] |= (1 << (diff % 8)); 155588768458SSam Leffler 1556de47c390SBjoern A. Zeeb /* Out of order but good. */ 155788768458SSam Leffler } 155888768458SSam Leffler 155988768458SSam Leffler ok: 156088768458SSam Leffler if (replay->count == ~0) { 156188768458SSam Leffler 1562de47c390SBjoern A. Zeeb /* Set overflow flag. */ 156388768458SSam Leffler replay->overflow++; 156488768458SSam Leffler 1565de47c390SBjoern A. Zeeb /* Don't increment, no more packets accepted. */ 156688768458SSam Leffler if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) 1567de47c390SBjoern A. Zeeb return (1); 156888768458SSam Leffler 15699ffa9677SSam Leffler ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 15709ffa9677SSam Leffler __func__, replay->overflow, ipsec_logsastr(sav))); 157188768458SSam Leffler } 157288768458SSam Leffler 157388768458SSam Leffler replay->count++; 157488768458SSam Leffler 1575de47c390SBjoern A. Zeeb return (0); 157688768458SSam Leffler } 157788768458SSam Leffler 157888768458SSam Leffler /* 1579de47c390SBjoern A. Zeeb * Shift variable length buffer to left. 158088768458SSam Leffler * IN: bitmap: pointer to the buffer 158188768458SSam Leffler * nbit: the number of to shift. 158288768458SSam Leffler * wsize: buffer size (bytes). 158388768458SSam Leffler */ 158488768458SSam Leffler static void 1585cd1a38f5SBjoern A. Zeeb vshiftl(unsigned char *bitmap, int nbit, int wsize) 158688768458SSam Leffler { 158788768458SSam Leffler int s, j, i; 158888768458SSam Leffler unsigned char over; 158988768458SSam Leffler 159088768458SSam Leffler for (j = 0; j < nbit; j += 8) { 159188768458SSam Leffler s = (nbit - j < 8) ? (nbit - j): 8; 159288768458SSam Leffler bitmap[0] <<= s; 159388768458SSam Leffler for (i = 1; i < wsize; i++) { 159488768458SSam Leffler over = (bitmap[i] >> (8 - s)); 159588768458SSam Leffler bitmap[i] <<= s; 159688768458SSam Leffler bitmap[i-1] |= over; 159788768458SSam Leffler } 159888768458SSam Leffler } 159988768458SSam Leffler } 160088768458SSam Leffler 1601fc228fbfSBjoern A. Zeeb #ifdef INET 160288768458SSam Leffler /* Return a printable string for the IPv4 address. */ 160388768458SSam Leffler static char * 160488768458SSam Leffler inet_ntoa4(struct in_addr ina) 160588768458SSam Leffler { 160688768458SSam Leffler static char buf[4][4 * sizeof "123" + 4]; 160788768458SSam Leffler unsigned char *ucp = (unsigned char *) &ina; 160888768458SSam Leffler static int i = 3; 160988768458SSam Leffler 1610de47c390SBjoern A. Zeeb /* XXX-BZ Returns static buffer. */ 161188768458SSam Leffler i = (i + 1) % 4; 161288768458SSam Leffler sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, 161388768458SSam Leffler ucp[2] & 0xff, ucp[3] & 0xff); 161488768458SSam Leffler return (buf[i]); 161588768458SSam Leffler } 1616fc228fbfSBjoern A. Zeeb #endif 161788768458SSam Leffler 161888768458SSam Leffler /* Return a printable string for the address. */ 161988768458SSam Leffler char * 162088768458SSam Leffler ipsec_address(union sockaddr_union* sa) 162188768458SSam Leffler { 1622224c45c4SBjoern A. Zeeb #ifdef INET6 16231d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 16241d54aa3bSBjoern A. Zeeb #endif 1625de47c390SBjoern A. Zeeb 162688768458SSam Leffler switch (sa->sa.sa_family) { 162749ddabdfSPawel Jakub Dawidek #ifdef INET 162888768458SSam Leffler case AF_INET: 1629de47c390SBjoern A. Zeeb return (inet_ntoa4(sa->sin.sin_addr)); 163088768458SSam Leffler #endif /* INET */ 163149ddabdfSPawel Jakub Dawidek #ifdef INET6 163288768458SSam Leffler case AF_INET6: 1633de47c390SBjoern A. Zeeb return (ip6_sprintf(ip6buf, &sa->sin6.sin6_addr)); 163488768458SSam Leffler #endif /* INET6 */ 163588768458SSam Leffler default: 1636de47c390SBjoern A. Zeeb return ("(unknown address family)"); 163788768458SSam Leffler } 163888768458SSam Leffler } 163988768458SSam Leffler 164088768458SSam Leffler const char * 1641cd1a38f5SBjoern A. Zeeb ipsec_logsastr(struct secasvar *sav) 164288768458SSam Leffler { 164388768458SSam Leffler static char buf[256]; 164488768458SSam Leffler char *p; 164588768458SSam Leffler struct secasindex *saidx = &sav->sah->saidx; 164688768458SSam Leffler 16479ffa9677SSam Leffler IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, 16489ffa9677SSam Leffler ("address family mismatch")); 164988768458SSam Leffler 165088768458SSam Leffler p = buf; 165188768458SSam Leffler snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); 165288768458SSam Leffler while (p && *p) 165388768458SSam Leffler p++; 1654de47c390SBjoern A. Zeeb /* NB: only use ipsec_address on one address at a time. */ 165588768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "src=%s ", 165688768458SSam Leffler ipsec_address(&saidx->src)); 165788768458SSam Leffler while (p && *p) 165888768458SSam Leffler p++; 165988768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", 166088768458SSam Leffler ipsec_address(&saidx->dst)); 166188768458SSam Leffler 1662de47c390SBjoern A. Zeeb return (buf); 166388768458SSam Leffler } 166488768458SSam Leffler 166588768458SSam Leffler void 1666cd1a38f5SBjoern A. Zeeb ipsec_dumpmbuf(struct mbuf *m) 166788768458SSam Leffler { 166888768458SSam Leffler int totlen; 166988768458SSam Leffler int i; 167088768458SSam Leffler u_char *p; 167188768458SSam Leffler 167288768458SSam Leffler totlen = 0; 167388768458SSam Leffler printf("---\n"); 167488768458SSam Leffler while (m) { 167588768458SSam Leffler p = mtod(m, u_char *); 167688768458SSam Leffler for (i = 0; i < m->m_len; i++) { 167788768458SSam Leffler printf("%02x ", p[i]); 167888768458SSam Leffler totlen++; 167988768458SSam Leffler if (totlen % 16 == 0) 168088768458SSam Leffler printf("\n"); 168188768458SSam Leffler } 168288768458SSam Leffler m = m->m_next; 168388768458SSam Leffler } 168488768458SSam Leffler if (totlen % 16 != 0) 168588768458SSam Leffler printf("\n"); 168688768458SSam Leffler printf("---\n"); 168788768458SSam Leffler } 168888768458SSam Leffler 16898381996eSSam Leffler static void 1690*93201211SAndrey V. Elsukov def_policy_init(const void *unused __unused) 16911ed81b73SMarko Zec { 16921ed81b73SMarko Zec 1693*93201211SAndrey V. Elsukov bzero(&V_def_policy, sizeof(struct secpolicy)); 1694*93201211SAndrey V. Elsukov V_def_policy.policy = IPSEC_POLICY_NONE; 1695*93201211SAndrey V. Elsukov V_def_policy.refcnt = 1; 16968381996eSSam Leffler } 1697*93201211SAndrey V. Elsukov VNET_SYSINIT(def_policy_init, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, 1698*93201211SAndrey V. Elsukov def_policy_init, NULL); 16998381996eSSam Leffler 17008381996eSSam Leffler 1701de47c390SBjoern A. Zeeb /* XXX This stuff doesn't belong here... */ 170288768458SSam Leffler 170388768458SSam Leffler static struct xformsw* xforms = NULL; 170488768458SSam Leffler 170588768458SSam Leffler /* 170688768458SSam Leffler * Register a transform; typically at system startup. 170788768458SSam Leffler */ 170888768458SSam Leffler void 170988768458SSam Leffler xform_register(struct xformsw* xsp) 171088768458SSam Leffler { 1711de47c390SBjoern A. Zeeb 171288768458SSam Leffler xsp->xf_next = xforms; 171388768458SSam Leffler xforms = xsp; 171488768458SSam Leffler } 171588768458SSam Leffler 171688768458SSam Leffler /* 171788768458SSam Leffler * Initialize transform support in an sav. 171888768458SSam Leffler */ 171988768458SSam Leffler int 172088768458SSam Leffler xform_init(struct secasvar *sav, int xftype) 172188768458SSam Leffler { 172288768458SSam Leffler struct xformsw *xsp; 172388768458SSam Leffler 1724de47c390SBjoern A. Zeeb if (sav->tdb_xform != NULL) /* Previously initialized. */ 1725de47c390SBjoern A. Zeeb return (0); 172688768458SSam Leffler for (xsp = xforms; xsp; xsp = xsp->xf_next) 172788768458SSam Leffler if (xsp->xf_type == xftype) 1728de47c390SBjoern A. Zeeb return ((*xsp->xf_init)(sav, xsp)); 1729de47c390SBjoern A. Zeeb return (EINVAL); 173088768458SSam Leffler } 1731