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> 56603724d3SBjoern A. Zeeb #include <sys/vimage.h> 5788768458SSam Leffler 5888768458SSam Leffler #include <net/if.h> 5988768458SSam Leffler #include <net/route.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 100385195c0SMarko Zec #ifndef VIMAGE 101385195c0SMarko Zec #ifndef VIMAGE_GLOBALS 102385195c0SMarko Zec struct vnet_ipsec vnet_ipsec_0; 103385195c0SMarko Zec #endif 104385195c0SMarko Zec #endif 105385195c0SMarko Zec 10644e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 107de47c390SBjoern A. Zeeb /* NB: name changed so netstat doesn't use it. */ 1082cb64cb2SGeorge V. Neville-Neil struct ipsecstat ipsec4stat; 10988768458SSam Leffler struct secpolicy ip4_def_policy; 11044e33a07SMarko Zec int ipsec_debug; 11144e33a07SMarko Zec int ip4_ah_offsetmask; 11244e33a07SMarko Zec int ip4_ipsec_dfbit; 11344e33a07SMarko Zec int ip4_esp_trans_deflev; 11444e33a07SMarko Zec int ip4_esp_net_deflev; 11544e33a07SMarko Zec int ip4_ah_trans_deflev; 11644e33a07SMarko Zec int ip4_ah_net_deflev; 11744e33a07SMarko Zec int ip4_ipsec_ecn; 11844e33a07SMarko Zec int ip4_esp_randpad; 11988768458SSam Leffler /* 12088768458SSam Leffler * Crypto support requirements: 12188768458SSam Leffler * 12288768458SSam Leffler * 1 require hardware support 12388768458SSam Leffler * -1 require software support 12488768458SSam Leffler * 0 take anything 12588768458SSam Leffler */ 12644e33a07SMarko Zec int crypto_support; 12744e33a07SMarko Zec #endif /* VIMAGE_GLOBALS */ 12888768458SSam Leffler 12988768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec); 13088768458SSam Leffler 13188768458SSam Leffler /* net.inet.ipsec */ 1328b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_POLICY, 1338b615593SMarko Zec def_policy, CTLFLAG_RW, ip4_def_policy.policy, 0, 134be6b1304STom Rhodes "IPsec default policy."); 1358b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, 1368b615593SMarko Zec esp_trans_deflev, CTLFLAG_RW, ip4_esp_trans_deflev, 0, 1378b615593SMarko Zec "Default ESP transport mode level"); 1388b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, 1398b615593SMarko Zec esp_net_deflev, CTLFLAG_RW, ip4_esp_net_deflev, 0, 1408b615593SMarko Zec "Default ESP tunnel mode level."); 1418b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, 1428b615593SMarko Zec ah_trans_deflev, CTLFLAG_RW, ip4_ah_trans_deflev, 0, 1438b615593SMarko Zec "AH transfer mode default level."); 1448b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, 1458b615593SMarko Zec ah_net_deflev, CTLFLAG_RW, ip4_ah_net_deflev, 0, 1468b615593SMarko Zec "AH tunnel mode default level."); 1478b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_CLEARTOS, 1488b615593SMarko Zec ah_cleartos, CTLFLAG_RW, ah_cleartos, 0, 1493377c961STom Rhodes "If set clear type-of-service field when doing AH computation."); 1508b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, 1518b615593SMarko Zec ah_offsetmask, CTLFLAG_RW, ip4_ah_offsetmask, 0, 1523377c961STom Rhodes "If not set clear offset field mask when doing AH computation."); 1538b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DFBIT, 1548b615593SMarko Zec dfbit, CTLFLAG_RW, ip4_ipsec_dfbit, 0, 1558b615593SMarko Zec "Do not fragment bit on encap."); 1568b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_ECN, 1578b615593SMarko Zec ecn, CTLFLAG_RW, ip4_ipsec_ecn, 0, 158be6b1304STom Rhodes "Explicit Congestion Notification handling."); 1598b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEBUG, 1608b615593SMarko Zec debug, CTLFLAG_RW, ipsec_debug, 0, 161be6b1304STom Rhodes "Enable IPsec debugging output when set."); 1628b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO, 1638b615593SMarko Zec crypto_support, CTLFLAG_RW, crypto_support,0, 164be6b1304STom Rhodes "Crypto driver selection."); 1658b615593SMarko Zec SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO, 1668b615593SMarko Zec ipsecstats, CTLFLAG_RD, ipsec4stat, ipsecstat, 1678b615593SMarko Zec "IPsec IPv4 statistics."); 16888768458SSam Leffler 1696131838bSPawel Jakub Dawidek #ifdef REGRESSION 17044e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 17144e33a07SMarko Zec int ipsec_replay; 17244e33a07SMarko Zec int ipsec_integrity; 17344e33a07SMarko Zec #endif 174dfa9422bSPawel Jakub Dawidek /* 175dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 176dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 177dfa9422bSPawel Jakub Dawidek */ 1788b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_replay, 1798b615593SMarko Zec CTLFLAG_RW, ipsec_replay, 0, "Emulate replay attack"); 180dfa9422bSPawel Jakub Dawidek /* 181dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 182dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 183dfa9422bSPawel Jakub Dawidek */ 1848b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_integrity, 1858b615593SMarko Zec CTLFLAG_RW, ipsec_integrity, 0, "Emulate man-in-the-middle attack"); 1866131838bSPawel Jakub Dawidek #endif 187dfa9422bSPawel Jakub Dawidek 18888768458SSam Leffler #ifdef INET6 18944e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 1902cb64cb2SGeorge V. Neville-Neil struct ipsecstat ipsec6stat; 19144e33a07SMarko Zec int ip6_esp_trans_deflev; 19244e33a07SMarko Zec int ip6_esp_net_deflev; 19344e33a07SMarko Zec int ip6_ah_trans_deflev; 19444e33a07SMarko Zec int ip6_ah_net_deflev; 19544e33a07SMarko Zec int ip6_ipsec_ecn; 19644e33a07SMarko Zec #endif 19788768458SSam Leffler 19888768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6); 19988768458SSam Leffler 20088768458SSam Leffler /* net.inet6.ipsec6 */ 20188768458SSam Leffler #ifdef COMPAT_KAME 20288768458SSam Leffler SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, 2033377c961STom Rhodes 0, 0, compat_ipsecstats_sysctl, "S", "IPsec IPv6 statistics."); 20488768458SSam Leffler #endif /* COMPAT_KAME */ 2058b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_POLICY, 2068b615593SMarko Zec def_policy, CTLFLAG_RW, ip4_def_policy.policy, 0, 2078b615593SMarko Zec "IPsec default policy."); 2088b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, 2098b615593SMarko Zec esp_trans_deflev, CTLFLAG_RW, ip6_esp_trans_deflev, 0, 2108b615593SMarko Zec "Default ESP transport mode level."); 2118b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, 2128b615593SMarko Zec esp_net_deflev, CTLFLAG_RW, ip6_esp_net_deflev, 0, 2138b615593SMarko Zec "Default ESP tunnel mode level."); 2148b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, 2158b615593SMarko Zec ah_trans_deflev, CTLFLAG_RW, ip6_ah_trans_deflev, 0, 2168b615593SMarko Zec "AH transfer mode default level."); 2178b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, 2188b615593SMarko Zec ah_net_deflev, CTLFLAG_RW, ip6_ah_net_deflev, 0, 2198b615593SMarko Zec "AH tunnel mode default level."); 2208b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_ECN, 2218b615593SMarko Zec ecn, CTLFLAG_RW, ip6_ipsec_ecn, 0, 2223377c961STom Rhodes "Explicit Congestion Notification handling."); 2238b615593SMarko Zec SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEBUG, 2248b615593SMarko Zec debug, CTLFLAG_RW, ipsec_debug, 0, 225be6b1304STom Rhodes "Enable IPsec debugging output when set."); 2268b615593SMarko Zec SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_STATS, 2278b615593SMarko Zec ipsecstats, CTLFLAG_RD, ipsec6stat, ipsecstat, 2288b615593SMarko Zec "IPsec IPv6 statistics."); 22988768458SSam Leffler #endif /* INET6 */ 23088768458SSam Leffler 23188768458SSam Leffler static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); 23288768458SSam Leffler #ifdef INET6 2331a12375fSBjoern A. Zeeb static int ipsec6_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); 23488768458SSam Leffler #endif 23588768458SSam Leffler static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); 23688768458SSam Leffler static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 23788768458SSam Leffler static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 23888768458SSam Leffler #ifdef INET6 23988768458SSam Leffler static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 24088768458SSam Leffler static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 24188768458SSam Leffler #endif 24288768458SSam Leffler static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); 24388768458SSam Leffler static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); 24488768458SSam Leffler static int ipsec_set_policy __P((struct secpolicy **pcb_sp, 245c26fe973SBjoern A. Zeeb int optname, caddr_t request, size_t len, struct ucred *cred)); 24688768458SSam Leffler static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); 24788768458SSam Leffler static void vshiftl __P((unsigned char *, int, int)); 24888768458SSam Leffler static size_t ipsec_hdrsiz __P((struct secpolicy *)); 24988768458SSam Leffler 2506464079fSSam Leffler MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); 2516464079fSSam Leffler 25244e33a07SMarko Zec void 25344e33a07SMarko Zec ipsec_init(void) 25444e33a07SMarko Zec { 25544e33a07SMarko Zec INIT_VNET_IPSEC(curvnet); 25644e33a07SMarko Zec 25744e33a07SMarko Zec #ifdef IPSEC_DEBUG 25844e33a07SMarko Zec V_ipsec_debug = 1; 25944e33a07SMarko Zec #else 26044e33a07SMarko Zec V_ipsec_debug = 0; 26144e33a07SMarko Zec #endif 26244e33a07SMarko Zec 26344e33a07SMarko Zec V_ip4_ah_offsetmask = 0; /* maybe IP_DF? */ 26444e33a07SMarko Zec V_ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ 26544e33a07SMarko Zec V_ip4_esp_trans_deflev = IPSEC_LEVEL_USE; 26644e33a07SMarko Zec V_ip4_esp_net_deflev = IPSEC_LEVEL_USE; 26744e33a07SMarko Zec V_ip4_ah_trans_deflev = IPSEC_LEVEL_USE; 26844e33a07SMarko Zec V_ip4_ah_net_deflev = IPSEC_LEVEL_USE; 26944e33a07SMarko Zec V_ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 27044e33a07SMarko Zec V_ip4_esp_randpad = -1; 27144e33a07SMarko Zec 27244e33a07SMarko Zec V_crypto_support = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 27344e33a07SMarko Zec 27444e33a07SMarko Zec #ifdef REGRESSION 27544e33a07SMarko Zec V_ipsec_replay = 0; 27644e33a07SMarko Zec V_ipsec_integrity = 0; 27744e33a07SMarko Zec #endif 27844e33a07SMarko Zec 279beac84a2SBjoern A. Zeeb #ifdef INET6 28044e33a07SMarko Zec V_ip6_esp_trans_deflev = IPSEC_LEVEL_USE; 28144e33a07SMarko Zec V_ip6_esp_net_deflev = IPSEC_LEVEL_USE; 28244e33a07SMarko Zec V_ip6_ah_trans_deflev = IPSEC_LEVEL_USE; 28344e33a07SMarko Zec V_ip6_ah_net_deflev = IPSEC_LEVEL_USE; 28444e33a07SMarko Zec V_ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 285beac84a2SBjoern A. Zeeb #endif 28644e33a07SMarko Zec } 28744e33a07SMarko Zec 28888768458SSam Leffler /* 28988768458SSam Leffler * Return a held reference to the default SP. 29088768458SSam Leffler */ 29188768458SSam Leffler static struct secpolicy * 29288768458SSam Leffler key_allocsp_default(const char* where, int tag) 29388768458SSam Leffler { 2948b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 29588768458SSam Leffler struct secpolicy *sp; 29688768458SSam Leffler 29788768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 29888768458SSam Leffler printf("DP key_allocsp_default from %s:%u\n", where, tag)); 29988768458SSam Leffler 300603724d3SBjoern A. Zeeb sp = &V_ip4_def_policy; 30188768458SSam Leffler if (sp->policy != IPSEC_POLICY_DISCARD && 30288768458SSam Leffler sp->policy != IPSEC_POLICY_NONE) { 30388768458SSam Leffler ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", 30488768458SSam Leffler sp->policy, IPSEC_POLICY_NONE)); 30588768458SSam Leffler sp->policy = IPSEC_POLICY_NONE; 30688768458SSam Leffler } 307422e4f5bSSam Leffler key_addref(sp); 30888768458SSam Leffler 30988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 31088768458SSam Leffler printf("DP key_allocsp_default returns SP:%p (%u)\n", 31188768458SSam Leffler sp, sp->refcnt)); 312de47c390SBjoern A. Zeeb return (sp); 31388768458SSam Leffler } 31488768458SSam Leffler #define KEY_ALLOCSP_DEFAULT() \ 31588768458SSam Leffler key_allocsp_default(__FILE__, __LINE__) 31688768458SSam Leffler 31788768458SSam Leffler /* 31888768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 31988768458SSam Leffler * and return a pointer to SP. 32088768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 32188768458SSam Leffler * 0 : bypass 32288768458SSam Leffler * EACCES : discard packet. 32388768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 32488768458SSam Leffler * others : error occured. 32588768458SSam Leffler * others: a pointer to SP 32688768458SSam Leffler * 32788768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 32888768458SSam Leffler */ 32988768458SSam Leffler struct secpolicy * 33088768458SSam Leffler ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) 33188768458SSam Leffler { 33288768458SSam Leffler struct secpolicy *sp; 33388768458SSam Leffler 3349ffa9677SSam Leffler IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); 3359ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3369ffa9677SSam Leffler ("invalid direction %u", dir)); 33788768458SSam Leffler 33888768458SSam Leffler sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); 33988768458SSam Leffler if (sp == NULL) /*XXX????*/ 34088768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 3419ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 342de47c390SBjoern A. Zeeb return (sp); 34388768458SSam Leffler } 34488768458SSam Leffler 34588768458SSam Leffler /* 34688768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 34788768458SSam Leffler * and return a pointer to SP. 34888768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 34988768458SSam Leffler * 0 : bypass 35088768458SSam Leffler * EACCES : discard packet. 35188768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 35288768458SSam Leffler * others : error occured. 35388768458SSam Leffler * others: a pointer to SP 35488768458SSam Leffler * 35588768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 35688768458SSam Leffler */ 357511080aeSBjoern A. Zeeb static struct secpolicy * 358511080aeSBjoern A. Zeeb ipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp, int *error) 35988768458SSam Leffler { 3608b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 36188768458SSam Leffler struct inpcbpolicy *pcbsp = NULL; 362de47c390SBjoern A. Zeeb struct secpolicy *currsp = NULL; /* Policy on socket. */ 36388768458SSam Leffler struct secpolicy *sp; 36488768458SSam Leffler 3659ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 3669ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inpcb")); 3679ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 3689ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3699ffa9677SSam Leffler ("invalid direction %u", dir)); 37088768458SSam Leffler 371de47c390SBjoern A. Zeeb /* Set spidx in pcb. */ 3729c3309d1SJonathan Lemon if (inp->inp_vflag & INP_IPV6PROTO) { 373595064e8SSam Leffler #ifdef INET6 3741a12375fSBjoern A. Zeeb *error = ipsec6_setspidx_inpcb(m, inp); 375fc384fa5SBjoern A. Zeeb pcbsp = inp->inp_sp; 376595064e8SSam Leffler #else 377de47c390SBjoern A. Zeeb *error = EINVAL; /* Should not happen. */ 378595064e8SSam Leffler #endif 3799c3309d1SJonathan Lemon } else { 3809c3309d1SJonathan Lemon *error = ipsec4_setspidx_inpcb(m, inp); 3819c3309d1SJonathan Lemon pcbsp = inp->inp_sp; 38288768458SSam Leffler } 38388768458SSam Leffler if (*error) 384de47c390SBjoern A. Zeeb return (NULL); 38588768458SSam Leffler 3869ffa9677SSam Leffler IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); 38788768458SSam Leffler switch (dir) { 38888768458SSam Leffler case IPSEC_DIR_INBOUND: 38988768458SSam Leffler currsp = pcbsp->sp_in; 39088768458SSam Leffler break; 39188768458SSam Leffler case IPSEC_DIR_OUTBOUND: 39288768458SSam Leffler currsp = pcbsp->sp_out; 39388768458SSam Leffler break; 39488768458SSam Leffler } 3959ffa9677SSam Leffler IPSEC_ASSERT(currsp != NULL, ("null currsp")); 39688768458SSam Leffler 397de47c390SBjoern A. Zeeb if (pcbsp->priv) { /* When privilieged socket. */ 39888768458SSam Leffler switch (currsp->policy) { 39988768458SSam Leffler case IPSEC_POLICY_BYPASS: 40088768458SSam Leffler case IPSEC_POLICY_IPSEC: 401422e4f5bSSam Leffler key_addref(currsp); 40288768458SSam Leffler sp = currsp; 40388768458SSam Leffler break; 40488768458SSam Leffler 40588768458SSam Leffler case IPSEC_POLICY_ENTRUST: 406de47c390SBjoern A. Zeeb /* Look for a policy in SPD. */ 40788768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 408de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found. */ 40988768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 41088768458SSam Leffler break; 41188768458SSam Leffler 41288768458SSam Leffler default: 4139ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", 4149ffa9677SSam Leffler __func__, currsp->policy)); 41588768458SSam Leffler *error = EINVAL; 416de47c390SBjoern A. Zeeb return (NULL); 41788768458SSam Leffler } 418de47c390SBjoern A. Zeeb } else { /* Unpriv, SPD has policy. */ 41988768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 420de47c390SBjoern A. Zeeb if (sp == NULL) { /* No SP found. */ 42188768458SSam Leffler switch (currsp->policy) { 42288768458SSam Leffler case IPSEC_POLICY_BYPASS: 4239ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Illegal policy for " 4249ffa9677SSam Leffler "non-priviliged defined %d\n", 4259ffa9677SSam Leffler __func__, currsp->policy)); 42688768458SSam Leffler *error = EINVAL; 427de47c390SBjoern A. Zeeb return (NULL); 42888768458SSam Leffler 42988768458SSam Leffler case IPSEC_POLICY_ENTRUST: 43088768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 43188768458SSam Leffler break; 43288768458SSam Leffler 43388768458SSam Leffler case IPSEC_POLICY_IPSEC: 434422e4f5bSSam Leffler key_addref(currsp); 43588768458SSam Leffler sp = currsp; 43688768458SSam Leffler break; 43788768458SSam Leffler 43888768458SSam Leffler default: 4399ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for " 4409ffa9677SSam Leffler "PCB %d\n", __func__, currsp->policy)); 44188768458SSam Leffler *error = EINVAL; 442de47c390SBjoern A. Zeeb return (NULL); 44388768458SSam Leffler } 44488768458SSam Leffler } 44588768458SSam Leffler } 4469ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, 4479ffa9677SSam Leffler ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); 44888768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 4499ffa9677SSam Leffler printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", 4509ffa9677SSam Leffler __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); 451de47c390SBjoern A. Zeeb return (sp); 45288768458SSam Leffler } 45388768458SSam Leffler 45488768458SSam Leffler /* 45588768458SSam Leffler * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, 45688768458SSam Leffler * and return a pointer to SP. 45788768458SSam Leffler * OUT: positive: a pointer to the entry for security policy leaf matched. 45888768458SSam Leffler * NULL: no apropreate SP found, the following value is set to error. 45988768458SSam Leffler * 0 : bypass 46088768458SSam Leffler * EACCES : discard packet. 46188768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 46288768458SSam Leffler * others : error occured. 46388768458SSam Leffler */ 46488768458SSam Leffler struct secpolicy * 465cd1a38f5SBjoern A. Zeeb ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error) 46688768458SSam Leffler { 4678b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 46888768458SSam Leffler struct secpolicyindex spidx; 46988768458SSam Leffler struct secpolicy *sp; 47088768458SSam Leffler 4719ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 4729ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 4739ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 4749ffa9677SSam Leffler ("invalid direction %u", dir)); 47588768458SSam Leffler 47688768458SSam Leffler sp = NULL; 47788768458SSam Leffler if (key_havesp(dir)) { 4789d5abbddSJens Schweikhardt /* Make an index to look for a policy. */ 47988768458SSam Leffler *error = ipsec_setspidx(m, &spidx, 48088768458SSam Leffler (flag & IP_FORWARDING) ? 0 : 1); 48188768458SSam Leffler if (*error != 0) { 4829ffa9677SSam Leffler DPRINTF(("%s: setpidx failed, dir %u flag %u\n", 4839ffa9677SSam Leffler __func__, dir, flag)); 484de47c390SBjoern A. Zeeb return (NULL); 48588768458SSam Leffler } 48688768458SSam Leffler spidx.dir = dir; 48788768458SSam Leffler 48888768458SSam Leffler sp = KEY_ALLOCSP(&spidx, dir); 48988768458SSam Leffler } 490de47c390SBjoern A. Zeeb if (sp == NULL) /* No SP found, use system default. */ 49188768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 4929ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 493de47c390SBjoern A. Zeeb return (sp); 49488768458SSam Leffler } 49588768458SSam Leffler 49688768458SSam Leffler struct secpolicy * 497cd1a38f5SBjoern A. Zeeb ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, 498cd1a38f5SBjoern A. Zeeb struct inpcb *inp) 49988768458SSam Leffler { 5008b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 50188768458SSam Leffler struct secpolicy *sp; 50288768458SSam Leffler 50388768458SSam Leffler *error = 0; 50488768458SSam Leffler if (inp == NULL) 50588768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, flag, error); 50688768458SSam Leffler else 50788768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, error); 50888768458SSam Leffler if (sp == NULL) { 5099ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); 510603724d3SBjoern A. Zeeb V_ipsec4stat.ips_out_inval++; 511de47c390SBjoern A. Zeeb return (NULL); 51288768458SSam Leffler } 5139ffa9677SSam Leffler IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); 51488768458SSam Leffler switch (sp->policy) { 51588768458SSam Leffler case IPSEC_POLICY_ENTRUST: 51688768458SSam Leffler default: 5179ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 518de47c390SBjoern A. Zeeb /* FALLTHROUGH */ 51988768458SSam Leffler case IPSEC_POLICY_DISCARD: 520603724d3SBjoern A. Zeeb V_ipsec4stat.ips_out_polvio++; 521de47c390SBjoern A. Zeeb *error = -EINVAL; /* Packet is discarded by caller. */ 52288768458SSam Leffler break; 52388768458SSam Leffler case IPSEC_POLICY_BYPASS: 52488768458SSam Leffler case IPSEC_POLICY_NONE: 52588768458SSam Leffler KEY_FREESP(&sp); 526de47c390SBjoern A. Zeeb sp = NULL; /* NB: force NULL result. */ 52788768458SSam Leffler break; 52888768458SSam Leffler case IPSEC_POLICY_IPSEC: 529de47c390SBjoern A. Zeeb if (sp->req == NULL) /* Acquire a SA. */ 53088768458SSam Leffler *error = key_spdacquire(sp); 53188768458SSam Leffler break; 53288768458SSam Leffler } 53388768458SSam Leffler if (*error != 0) { 53488768458SSam Leffler KEY_FREESP(&sp); 53588768458SSam Leffler sp = NULL; 53688768458SSam Leffler } 537de47c390SBjoern A. Zeeb return (sp); 53888768458SSam Leffler } 53988768458SSam Leffler 54088768458SSam Leffler static int 541cd1a38f5SBjoern A. Zeeb ipsec4_setspidx_inpcb(struct mbuf *m, struct inpcb *pcb) 54288768458SSam Leffler { 54388768458SSam Leffler int error; 54488768458SSam Leffler 5459ffa9677SSam Leffler IPSEC_ASSERT(pcb != NULL, ("null pcb")); 5469ffa9677SSam Leffler IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); 5479ffa9677SSam Leffler IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, 5489ffa9677SSam Leffler ("null sp_in || sp_out")); 54988768458SSam Leffler 55088768458SSam Leffler error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); 55188768458SSam Leffler if (error == 0) { 55288768458SSam Leffler pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 55388768458SSam Leffler pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; 55488768458SSam Leffler pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 55588768458SSam Leffler } else { 55688768458SSam Leffler bzero(&pcb->inp_sp->sp_in->spidx, 55788768458SSam Leffler sizeof (pcb->inp_sp->sp_in->spidx)); 55888768458SSam Leffler bzero(&pcb->inp_sp->sp_out->spidx, 55988768458SSam Leffler sizeof (pcb->inp_sp->sp_in->spidx)); 56088768458SSam Leffler } 561de47c390SBjoern A. Zeeb return (error); 56288768458SSam Leffler } 56388768458SSam Leffler 56488768458SSam Leffler #ifdef INET6 56588768458SSam Leffler static int 566cd1a38f5SBjoern A. Zeeb ipsec6_setspidx_inpcb(struct mbuf *m, struct inpcb *pcb) 56788768458SSam Leffler { 56888768458SSam Leffler int error; 56988768458SSam Leffler 5709ffa9677SSam Leffler IPSEC_ASSERT(pcb != NULL, ("null pcb")); 571fc384fa5SBjoern A. Zeeb IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); 572fc384fa5SBjoern A. Zeeb IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, 5739ffa9677SSam Leffler ("null sp_in || sp_out")); 57488768458SSam Leffler 575b63904a1SBjoern A. Zeeb error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); 576b63904a1SBjoern A. Zeeb if (error == 0) { 577b63904a1SBjoern A. Zeeb pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 578b63904a1SBjoern A. Zeeb pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; 579b63904a1SBjoern A. Zeeb pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 580b63904a1SBjoern A. Zeeb } else { 581b63904a1SBjoern A. Zeeb bzero(&pcb->inp_sp->sp_in->spidx, 582b63904a1SBjoern A. Zeeb sizeof(pcb->inp_sp->sp_in->spidx)); 583b63904a1SBjoern A. Zeeb bzero(&pcb->inp_sp->sp_out->spidx, 584b63904a1SBjoern A. Zeeb sizeof(pcb->inp_sp->sp_in->spidx)); 585b63904a1SBjoern A. Zeeb } 58688768458SSam Leffler 587de47c390SBjoern A. Zeeb return (error); 58888768458SSam Leffler } 58988768458SSam Leffler #endif 59088768458SSam Leffler 59188768458SSam Leffler /* 592de47c390SBjoern A. Zeeb * Configure security policy index (src/dst/proto/sport/dport) 59388768458SSam Leffler * by looking at the content of mbuf. 594de47c390SBjoern A. Zeeb * The caller is responsible for error recovery (like clearing up spidx). 59588768458SSam Leffler */ 59688768458SSam Leffler static int 597cd1a38f5SBjoern A. Zeeb ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) 59888768458SSam Leffler { 5998b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 60088768458SSam Leffler struct ip *ip = NULL; 60188768458SSam Leffler struct ip ipbuf; 60288768458SSam Leffler u_int v; 60388768458SSam Leffler struct mbuf *n; 60488768458SSam Leffler int len; 60588768458SSam Leffler int error; 60688768458SSam Leffler 6079ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 60888768458SSam Leffler 60988768458SSam Leffler /* 610de47c390SBjoern A. Zeeb * Validate m->m_pkthdr.len. We see incorrect length if we 61188768458SSam Leffler * mistakenly call this function with inconsistent mbuf chain 612de47c390SBjoern A. Zeeb * (like 4.4BSD tcp/udp processing). XXX Should we panic here? 61388768458SSam Leffler */ 61488768458SSam Leffler len = 0; 61588768458SSam Leffler for (n = m; n; n = n->m_next) 61688768458SSam Leffler len += n->m_len; 61788768458SSam Leffler if (m->m_pkthdr.len != len) { 61888768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6199ffa9677SSam Leffler printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", 6209ffa9677SSam Leffler __func__, len, m->m_pkthdr.len)); 621de47c390SBjoern A. Zeeb return (EINVAL); 62288768458SSam Leffler } 62388768458SSam Leffler 62488768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip)) { 62588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6269ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v4), ignored.\n", 6279ffa9677SSam Leffler __func__, m->m_pkthdr.len)); 628de47c390SBjoern A. Zeeb return (EINVAL); 62988768458SSam Leffler } 63088768458SSam Leffler 63188768458SSam Leffler if (m->m_len >= sizeof(*ip)) 63288768458SSam Leffler ip = mtod(m, struct ip *); 63388768458SSam Leffler else { 63488768458SSam Leffler m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); 63588768458SSam Leffler ip = &ipbuf; 63688768458SSam Leffler } 63788768458SSam Leffler #ifdef _IP_VHL 63888768458SSam Leffler v = _IP_VHL_V(ip->ip_vhl); 63988768458SSam Leffler #else 64088768458SSam Leffler v = ip->ip_v; 64188768458SSam Leffler #endif 64288768458SSam Leffler switch (v) { 64388768458SSam Leffler case 4: 64488768458SSam Leffler error = ipsec4_setspidx_ipaddr(m, spidx); 64588768458SSam Leffler if (error) 646de47c390SBjoern A. Zeeb return (error); 64788768458SSam Leffler ipsec4_get_ulp(m, spidx, needport); 648de47c390SBjoern A. Zeeb return (0); 64988768458SSam Leffler #ifdef INET6 65088768458SSam Leffler case 6: 65188768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { 65288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6539ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v6), " 6549ffa9677SSam Leffler "ignored\n", __func__, m->m_pkthdr.len)); 655de47c390SBjoern A. Zeeb return (EINVAL); 65688768458SSam Leffler } 65788768458SSam Leffler error = ipsec6_setspidx_ipaddr(m, spidx); 65888768458SSam Leffler if (error) 659de47c390SBjoern A. Zeeb return (error); 66088768458SSam Leffler ipsec6_get_ulp(m, spidx, needport); 661de47c390SBjoern A. Zeeb return (0); 66288768458SSam Leffler #endif 66388768458SSam Leffler default: 66488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6659ffa9677SSam Leffler printf("%s: " "unknown IP version %u, ignored.\n", 6669ffa9677SSam Leffler __func__, v)); 667de47c390SBjoern A. Zeeb return (EINVAL); 66888768458SSam Leffler } 66988768458SSam Leffler } 67088768458SSam Leffler 67188768458SSam Leffler static void 67288768458SSam Leffler ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 67388768458SSam Leffler { 67488768458SSam Leffler u_int8_t nxt; 67588768458SSam Leffler int off; 67688768458SSam Leffler 677de47c390SBjoern A. Zeeb /* Sanity check. */ 6789ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 6799ffa9677SSam Leffler IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); 68088768458SSam Leffler 681de47c390SBjoern A. Zeeb /* NB: ip_input() flips it into host endian. XXX Need more checking. */ 68288768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 68388768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 68488768458SSam Leffler if (ip->ip_off & (IP_MF | IP_OFFMASK)) 68588768458SSam Leffler goto done; 68688768458SSam Leffler #ifdef _IP_VHL 68788768458SSam Leffler off = _IP_VHL_HL(ip->ip_vhl) << 2; 68888768458SSam Leffler #else 68988768458SSam Leffler off = ip->ip_hl << 2; 69088768458SSam Leffler #endif 69188768458SSam Leffler nxt = ip->ip_p; 69288768458SSam Leffler } else { 69388768458SSam Leffler struct ip ih; 69488768458SSam Leffler 69588768458SSam Leffler m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 69688768458SSam Leffler if (ih.ip_off & (IP_MF | IP_OFFMASK)) 69788768458SSam Leffler goto done; 69888768458SSam Leffler #ifdef _IP_VHL 69988768458SSam Leffler off = _IP_VHL_HL(ih.ip_vhl) << 2; 70088768458SSam Leffler #else 70188768458SSam Leffler off = ih.ip_hl << 2; 70288768458SSam Leffler #endif 70388768458SSam Leffler nxt = ih.ip_p; 70488768458SSam Leffler } 70588768458SSam Leffler 70688768458SSam Leffler while (off < m->m_pkthdr.len) { 70788768458SSam Leffler struct ip6_ext ip6e; 70888768458SSam Leffler struct tcphdr th; 70988768458SSam Leffler struct udphdr uh; 71088768458SSam Leffler 71188768458SSam Leffler switch (nxt) { 71288768458SSam Leffler case IPPROTO_TCP: 71388768458SSam Leffler spidx->ul_proto = nxt; 71488768458SSam Leffler if (!needport) 71588768458SSam Leffler goto done_proto; 71688768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 71788768458SSam Leffler goto done; 71888768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 71988768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 72088768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 72188768458SSam Leffler return; 72288768458SSam Leffler case IPPROTO_UDP: 72388768458SSam Leffler spidx->ul_proto = nxt; 72488768458SSam Leffler if (!needport) 72588768458SSam Leffler goto done_proto; 72688768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 72788768458SSam Leffler goto done; 72888768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 72988768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 73088768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 73188768458SSam Leffler return; 73288768458SSam Leffler case IPPROTO_AH: 733afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 73488768458SSam Leffler goto done; 735de47c390SBjoern A. Zeeb /* XXX Sigh, this works but is totally bogus. */ 73688768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 73788768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 73888768458SSam Leffler nxt = ip6e.ip6e_nxt; 73988768458SSam Leffler break; 74088768458SSam Leffler case IPPROTO_ICMP: 74188768458SSam Leffler default: 742de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 74388768458SSam Leffler spidx->ul_proto = nxt; 74488768458SSam Leffler goto done_proto; 74588768458SSam Leffler } 74688768458SSam Leffler } 74788768458SSam Leffler done: 74888768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 74988768458SSam Leffler done_proto: 75088768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 75188768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 75288768458SSam Leffler } 75388768458SSam Leffler 754de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 75588768458SSam Leffler static int 75688768458SSam Leffler ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 75788768458SSam Leffler { 75888768458SSam Leffler static const struct sockaddr_in template = { 75988768458SSam Leffler sizeof (struct sockaddr_in), 76088768458SSam Leffler AF_INET, 76188768458SSam Leffler 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 76288768458SSam Leffler }; 76388768458SSam Leffler 76488768458SSam Leffler spidx->src.sin = template; 76588768458SSam Leffler spidx->dst.sin = template; 76688768458SSam Leffler 76788768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 76888768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_src), 76988768458SSam Leffler sizeof (struct in_addr), 77088768458SSam Leffler (caddr_t) &spidx->src.sin.sin_addr); 77188768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_dst), 77288768458SSam Leffler sizeof (struct in_addr), 77388768458SSam Leffler (caddr_t) &spidx->dst.sin.sin_addr); 77488768458SSam Leffler } else { 77588768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 77688768458SSam Leffler spidx->src.sin.sin_addr = ip->ip_src; 77788768458SSam Leffler spidx->dst.sin.sin_addr = ip->ip_dst; 77888768458SSam Leffler } 77988768458SSam Leffler 78088768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 78188768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 78288768458SSam Leffler 783de47c390SBjoern A. Zeeb return (0); 78488768458SSam Leffler } 78588768458SSam Leffler 78688768458SSam Leffler #ifdef INET6 78788768458SSam Leffler static void 788cd1a38f5SBjoern A. Zeeb ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 78988768458SSam Leffler { 7908b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 79188768458SSam Leffler int off, nxt; 79288768458SSam Leffler struct tcphdr th; 79388768458SSam Leffler struct udphdr uh; 7940e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 79588768458SSam Leffler 796de47c390SBjoern A. Zeeb /* Sanity check. */ 79788768458SSam Leffler if (m == NULL) 7989ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 79988768458SSam Leffler 80088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 8019ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(m)); 80288768458SSam Leffler 803de47c390SBjoern A. Zeeb /* Set default. */ 80488768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 80588768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; 80688768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; 80788768458SSam Leffler 80888768458SSam Leffler nxt = -1; 80988768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 81088768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 81188768458SSam Leffler return; 81288768458SSam Leffler 81388768458SSam Leffler switch (nxt) { 81488768458SSam Leffler case IPPROTO_TCP: 81588768458SSam Leffler spidx->ul_proto = nxt; 81688768458SSam Leffler if (!needport) 81788768458SSam Leffler break; 81888768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 81988768458SSam Leffler break; 82088768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 82188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; 82288768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; 82388768458SSam Leffler break; 82488768458SSam Leffler case IPPROTO_UDP: 82588768458SSam Leffler spidx->ul_proto = nxt; 82688768458SSam Leffler if (!needport) 82788768458SSam Leffler break; 82888768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 82988768458SSam Leffler break; 83088768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 83188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; 83288768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; 83388768458SSam Leffler break; 83488768458SSam Leffler case IPPROTO_ICMPV6: 8350e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 8360e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 8370e3c2be4SBjoern A. Zeeb break; 8380e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 8390e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->src)->sin6_port = 8400e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_type); 8410e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = 8420e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_code); 8430e3c2be4SBjoern A. Zeeb break; 84488768458SSam Leffler default: 845de47c390SBjoern A. Zeeb /* XXX Intermediate headers??? */ 84688768458SSam Leffler spidx->ul_proto = nxt; 84788768458SSam Leffler break; 84888768458SSam Leffler } 84988768458SSam Leffler } 85088768458SSam Leffler 851de47c390SBjoern A. Zeeb /* Assumes that m is sane. */ 85288768458SSam Leffler static int 853cd1a38f5SBjoern A. Zeeb ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 85488768458SSam Leffler { 85588768458SSam Leffler struct ip6_hdr *ip6 = NULL; 85688768458SSam Leffler struct ip6_hdr ip6buf; 85788768458SSam Leffler struct sockaddr_in6 *sin6; 85888768458SSam Leffler 85988768458SSam Leffler if (m->m_len >= sizeof(*ip6)) 86088768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 86188768458SSam Leffler else { 86288768458SSam Leffler m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 86388768458SSam Leffler ip6 = &ip6buf; 86488768458SSam Leffler } 86588768458SSam Leffler 86688768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->src; 86788768458SSam Leffler bzero(sin6, sizeof(*sin6)); 86888768458SSam Leffler sin6->sin6_family = AF_INET6; 86988768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 87088768458SSam Leffler bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); 87188768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 87288768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 87388768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); 87488768458SSam Leffler } 87588768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 87688768458SSam Leffler 87788768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->dst; 87888768458SSam Leffler bzero(sin6, sizeof(*sin6)); 87988768458SSam Leffler sin6->sin6_family = AF_INET6; 88088768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 88188768458SSam Leffler bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); 88288768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 88388768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 88488768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); 88588768458SSam Leffler } 88688768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 88788768458SSam Leffler 888de47c390SBjoern A. Zeeb return (0); 88988768458SSam Leffler } 89088768458SSam Leffler #endif 89188768458SSam Leffler 89288768458SSam Leffler static void 893cd1a38f5SBjoern A. Zeeb ipsec_delpcbpolicy(struct inpcbpolicy *p) 89488768458SSam Leffler { 895de47c390SBjoern A. Zeeb 8966464079fSSam Leffler free(p, M_IPSEC_INPCB); 89788768458SSam Leffler } 89888768458SSam Leffler 899de47c390SBjoern A. Zeeb /* Initialize policy in PCB. */ 90088768458SSam Leffler int 901cd1a38f5SBjoern A. Zeeb ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) 90288768458SSam Leffler { 9038b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 90488768458SSam Leffler struct inpcbpolicy *new; 90588768458SSam Leffler 906de47c390SBjoern A. Zeeb /* Sanity check. */ 90788768458SSam Leffler if (so == NULL || pcb_sp == NULL) 9089ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 90988768458SSam Leffler 91088768458SSam Leffler new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), 9116464079fSSam Leffler M_IPSEC_INPCB, M_NOWAIT|M_ZERO); 91288768458SSam Leffler if (new == NULL) { 9139ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 914de47c390SBjoern A. Zeeb return (ENOBUFS); 91588768458SSam Leffler } 91688768458SSam Leffler 9179ffa9677SSam Leffler new->priv = IPSEC_IS_PRIVILEGED_SO(so); 91888768458SSam Leffler 91988768458SSam Leffler if ((new->sp_in = KEY_NEWSP()) == NULL) { 92088768458SSam Leffler ipsec_delpcbpolicy(new); 921de47c390SBjoern A. Zeeb return (ENOBUFS); 92288768458SSam Leffler } 92388768458SSam Leffler new->sp_in->state = IPSEC_SPSTATE_ALIVE; 92488768458SSam Leffler new->sp_in->policy = IPSEC_POLICY_ENTRUST; 92588768458SSam Leffler 92688768458SSam Leffler if ((new->sp_out = KEY_NEWSP()) == NULL) { 92788768458SSam Leffler KEY_FREESP(&new->sp_in); 92888768458SSam Leffler ipsec_delpcbpolicy(new); 929de47c390SBjoern A. Zeeb return (ENOBUFS); 93088768458SSam Leffler } 93188768458SSam Leffler new->sp_out->state = IPSEC_SPSTATE_ALIVE; 93288768458SSam Leffler new->sp_out->policy = IPSEC_POLICY_ENTRUST; 93388768458SSam Leffler 93488768458SSam Leffler *pcb_sp = new; 93588768458SSam Leffler 936de47c390SBjoern A. Zeeb return (0); 93788768458SSam Leffler } 93888768458SSam Leffler 939de47c390SBjoern A. Zeeb /* Copy old IPsec policy into new. */ 94088768458SSam Leffler int 941cd1a38f5SBjoern A. Zeeb ipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new) 94288768458SSam Leffler { 94388768458SSam Leffler struct secpolicy *sp; 94488768458SSam Leffler 94588768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_in); 94688768458SSam Leffler if (sp) { 94788768458SSam Leffler KEY_FREESP(&new->sp_in); 94888768458SSam Leffler new->sp_in = sp; 94988768458SSam Leffler } else 950de47c390SBjoern A. Zeeb return (ENOBUFS); 95188768458SSam Leffler 95288768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_out); 95388768458SSam Leffler if (sp) { 95488768458SSam Leffler KEY_FREESP(&new->sp_out); 95588768458SSam Leffler new->sp_out = sp; 95688768458SSam Leffler } else 957de47c390SBjoern A. Zeeb return (ENOBUFS); 95888768458SSam Leffler 95988768458SSam Leffler new->priv = old->priv; 96088768458SSam Leffler 961de47c390SBjoern A. Zeeb return (0); 96288768458SSam Leffler } 96388768458SSam Leffler 9646464079fSSam Leffler struct ipsecrequest * 9656464079fSSam Leffler ipsec_newisr(void) 9666464079fSSam Leffler { 9676464079fSSam Leffler struct ipsecrequest *p; 9686464079fSSam Leffler 9696464079fSSam Leffler p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); 9706464079fSSam Leffler if (p != NULL) 9719ffa9677SSam Leffler IPSECREQUEST_LOCK_INIT(p); 972de47c390SBjoern A. Zeeb return (p); 9736464079fSSam Leffler } 9746464079fSSam Leffler 9756464079fSSam Leffler void 9766464079fSSam Leffler ipsec_delisr(struct ipsecrequest *p) 9776464079fSSam Leffler { 978de47c390SBjoern A. Zeeb 9799ffa9677SSam Leffler IPSECREQUEST_LOCK_DESTROY(p); 9806464079fSSam Leffler free(p, M_IPSEC_SR); 9816464079fSSam Leffler } 9826464079fSSam Leffler 983de47c390SBjoern A. Zeeb /* Deep-copy a policy in PCB. */ 98488768458SSam Leffler static struct secpolicy * 985cd1a38f5SBjoern A. Zeeb ipsec_deepcopy_policy(struct secpolicy *src) 98688768458SSam Leffler { 98788768458SSam Leffler struct ipsecrequest *newchain = NULL; 98888768458SSam Leffler struct ipsecrequest *p; 98988768458SSam Leffler struct ipsecrequest **q; 99088768458SSam Leffler struct ipsecrequest *r; 99188768458SSam Leffler struct secpolicy *dst; 99288768458SSam Leffler 99388768458SSam Leffler if (src == NULL) 994de47c390SBjoern A. Zeeb return (NULL); 99588768458SSam Leffler dst = KEY_NEWSP(); 99688768458SSam Leffler if (dst == NULL) 997de47c390SBjoern A. Zeeb return (NULL); 99888768458SSam Leffler 99988768458SSam Leffler /* 1000de47c390SBjoern A. Zeeb * Deep-copy IPsec request chain. This is required since struct 100188768458SSam Leffler * ipsecrequest is not reference counted. 100288768458SSam Leffler */ 100388768458SSam Leffler q = &newchain; 100488768458SSam Leffler for (p = src->req; p; p = p->next) { 10056464079fSSam Leffler *q = ipsec_newisr(); 100688768458SSam Leffler if (*q == NULL) 100788768458SSam Leffler goto fail; 100888768458SSam Leffler (*q)->saidx.proto = p->saidx.proto; 100988768458SSam Leffler (*q)->saidx.mode = p->saidx.mode; 101088768458SSam Leffler (*q)->level = p->level; 101188768458SSam Leffler (*q)->saidx.reqid = p->saidx.reqid; 101288768458SSam Leffler 101388768458SSam Leffler bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); 101488768458SSam Leffler bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); 101588768458SSam Leffler 101688768458SSam Leffler (*q)->sp = dst; 101788768458SSam Leffler 101888768458SSam Leffler q = &((*q)->next); 101988768458SSam Leffler } 102088768458SSam Leffler 102188768458SSam Leffler dst->req = newchain; 102288768458SSam Leffler dst->state = src->state; 102388768458SSam Leffler dst->policy = src->policy; 1024de47c390SBjoern A. Zeeb /* Do not touch the refcnt fields. */ 102588768458SSam Leffler 1026de47c390SBjoern A. Zeeb return (dst); 102788768458SSam Leffler 102888768458SSam Leffler fail: 102988768458SSam Leffler for (p = newchain; p; p = r) { 103088768458SSam Leffler r = p->next; 10316464079fSSam Leffler ipsec_delisr(p); 103288768458SSam Leffler p = NULL; 103388768458SSam Leffler } 1034de47c390SBjoern A. Zeeb return (NULL); 103588768458SSam Leffler } 103688768458SSam Leffler 1037de47c390SBjoern A. Zeeb /* Set policy and IPsec request if present. */ 103888768458SSam Leffler static int 1039cd1a38f5SBjoern A. Zeeb ipsec_set_policy(struct secpolicy **pcb_sp, int optname, caddr_t request, 1040cd1a38f5SBjoern A. Zeeb size_t len, struct ucred *cred) 104188768458SSam Leffler { 10428b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 104388768458SSam Leffler struct sadb_x_policy *xpl; 104488768458SSam Leffler struct secpolicy *newsp = NULL; 104588768458SSam Leffler int error; 104688768458SSam Leffler 1047de47c390SBjoern A. Zeeb /* Sanity check. */ 104888768458SSam Leffler if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) 1049de47c390SBjoern A. Zeeb return (EINVAL); 105088768458SSam Leffler if (len < sizeof(*xpl)) 1051de47c390SBjoern A. Zeeb return (EINVAL); 105288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 105388768458SSam Leffler 105488768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10559ffa9677SSam Leffler printf("%s: passed policy\n", __func__); 105688768458SSam Leffler kdebug_sadb_x_policy((struct sadb_ext *)xpl)); 105788768458SSam Leffler 1058de47c390SBjoern A. Zeeb /* Check policy type. */ 105988768458SSam Leffler /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ 106088768458SSam Leffler if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD 106188768458SSam Leffler || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) 1062de47c390SBjoern A. Zeeb return (EINVAL); 106388768458SSam Leffler 1064de47c390SBjoern A. Zeeb /* Check privileged socket. */ 1065c26fe973SBjoern A. Zeeb if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { 1066c26fe973SBjoern A. Zeeb error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); 1067c26fe973SBjoern A. Zeeb if (error) 1068de47c390SBjoern A. Zeeb return (EACCES); 1069c26fe973SBjoern A. Zeeb } 107088768458SSam Leffler 1071de47c390SBjoern A. Zeeb /* Allocating new SP entry. */ 107288768458SSam Leffler if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) 1073de47c390SBjoern A. Zeeb return (error); 107488768458SSam Leffler 107588768458SSam Leffler newsp->state = IPSEC_SPSTATE_ALIVE; 107688768458SSam Leffler 1077de47c390SBjoern A. Zeeb /* Clear old SP and set new SP. */ 107888768458SSam Leffler KEY_FREESP(pcb_sp); 107988768458SSam Leffler *pcb_sp = newsp; 108088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10819ffa9677SSam Leffler printf("%s: new policy\n", __func__); 108288768458SSam Leffler kdebug_secpolicy(newsp)); 108388768458SSam Leffler 1084de47c390SBjoern A. Zeeb return (0); 108588768458SSam Leffler } 108688768458SSam Leffler 108788768458SSam Leffler static int 1088cd1a38f5SBjoern A. Zeeb ipsec_get_policy(struct secpolicy *pcb_sp, struct mbuf **mp) 108988768458SSam Leffler { 10908b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 109188768458SSam Leffler 1092de47c390SBjoern A. Zeeb /* Sanity check. */ 109388768458SSam Leffler if (pcb_sp == NULL || mp == NULL) 1094de47c390SBjoern A. Zeeb return (EINVAL); 109588768458SSam Leffler 109688768458SSam Leffler *mp = key_sp2msg(pcb_sp); 109788768458SSam Leffler if (!*mp) { 10989ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 1099de47c390SBjoern A. Zeeb return (ENOBUFS); 110088768458SSam Leffler } 110188768458SSam Leffler 110288768458SSam Leffler (*mp)->m_type = MT_DATA; 110388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 11049ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(*mp)); 110588768458SSam Leffler 1106de47c390SBjoern A. Zeeb return (0); 110788768458SSam Leffler } 110888768458SSam Leffler 110988768458SSam Leffler int 1110cd1a38f5SBjoern A. Zeeb ipsec4_set_policy(struct inpcb *inp, int optname, caddr_t request, 1111cd1a38f5SBjoern A. Zeeb size_t len, struct ucred *cred) 111288768458SSam Leffler { 11138b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 111488768458SSam Leffler struct sadb_x_policy *xpl; 111588768458SSam Leffler struct secpolicy **pcb_sp; 111688768458SSam Leffler 1117de47c390SBjoern A. Zeeb /* Sanity check. */ 111888768458SSam Leffler if (inp == NULL || request == NULL) 1119de47c390SBjoern A. Zeeb return (EINVAL); 112088768458SSam Leffler if (len < sizeof(*xpl)) 1121de47c390SBjoern A. Zeeb return (EINVAL); 112288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 112388768458SSam Leffler 1124de47c390SBjoern A. Zeeb /* Select direction. */ 112588768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 112688768458SSam Leffler case IPSEC_DIR_INBOUND: 112788768458SSam Leffler pcb_sp = &inp->inp_sp->sp_in; 112888768458SSam Leffler break; 112988768458SSam Leffler case IPSEC_DIR_OUTBOUND: 113088768458SSam Leffler pcb_sp = &inp->inp_sp->sp_out; 113188768458SSam Leffler break; 113288768458SSam Leffler default: 11339ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 113488768458SSam Leffler xpl->sadb_x_policy_dir)); 1135de47c390SBjoern A. Zeeb return (EINVAL); 113688768458SSam Leffler } 113788768458SSam Leffler 1138de47c390SBjoern A. Zeeb return (ipsec_set_policy(pcb_sp, optname, request, len, cred)); 113988768458SSam Leffler } 114088768458SSam Leffler 114188768458SSam Leffler int 1142cd1a38f5SBjoern A. Zeeb ipsec4_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1143cd1a38f5SBjoern A. Zeeb struct mbuf **mp) 114488768458SSam Leffler { 11458b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 114688768458SSam Leffler struct sadb_x_policy *xpl; 114788768458SSam Leffler struct secpolicy *pcb_sp; 114888768458SSam Leffler 1149de47c390SBjoern A. Zeeb /* Sanity check. */ 115088768458SSam Leffler if (inp == NULL || request == NULL || mp == NULL) 1151de47c390SBjoern A. Zeeb return (EINVAL); 11529ffa9677SSam Leffler IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 115388768458SSam Leffler if (len < sizeof(*xpl)) 1154de47c390SBjoern A. Zeeb return (EINVAL); 115588768458SSam Leffler xpl = (struct sadb_x_policy *)request; 115688768458SSam Leffler 1157de47c390SBjoern A. Zeeb /* Select direction. */ 115888768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 115988768458SSam Leffler case IPSEC_DIR_INBOUND: 116088768458SSam Leffler pcb_sp = inp->inp_sp->sp_in; 116188768458SSam Leffler break; 116288768458SSam Leffler case IPSEC_DIR_OUTBOUND: 116388768458SSam Leffler pcb_sp = inp->inp_sp->sp_out; 116488768458SSam Leffler break; 116588768458SSam Leffler default: 11669ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 116788768458SSam Leffler xpl->sadb_x_policy_dir)); 1168de47c390SBjoern A. Zeeb return (EINVAL); 116988768458SSam Leffler } 117088768458SSam Leffler 1171de47c390SBjoern A. Zeeb return (ipsec_get_policy(pcb_sp, mp)); 117288768458SSam Leffler } 117388768458SSam Leffler 1174de47c390SBjoern A. Zeeb /* Delete policy in PCB. */ 117588768458SSam Leffler int 1176cd1a38f5SBjoern A. Zeeb ipsec_delete_pcbpolicy(struct inpcb *inp) 117788768458SSam Leffler { 11789ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inp")); 117988768458SSam Leffler 118088768458SSam Leffler if (inp->inp_sp == NULL) 1181de47c390SBjoern A. Zeeb return (0); 118288768458SSam Leffler 118388768458SSam Leffler if (inp->inp_sp->sp_in != NULL) 118488768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_in); 118588768458SSam Leffler 118688768458SSam Leffler if (inp->inp_sp->sp_out != NULL) 118788768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_out); 118888768458SSam Leffler 118988768458SSam Leffler ipsec_delpcbpolicy(inp->inp_sp); 119088768458SSam Leffler inp->inp_sp = NULL; 119188768458SSam Leffler 1192de47c390SBjoern A. Zeeb return (0); 119388768458SSam Leffler } 119488768458SSam Leffler 119588768458SSam Leffler #ifdef INET6 119688768458SSam Leffler int 1197cd1a38f5SBjoern A. Zeeb ipsec6_set_policy(struct inpcb *inp, int optname, caddr_t request, 1198cd1a38f5SBjoern A. Zeeb size_t len, struct ucred *cred) 119988768458SSam Leffler { 12008b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 120188768458SSam Leffler struct sadb_x_policy *xpl; 120288768458SSam Leffler struct secpolicy **pcb_sp; 120388768458SSam Leffler 1204de47c390SBjoern A. Zeeb /* Sanity check. */ 120528097b18SBjoern A. Zeeb if (inp == NULL || request == NULL) 1206de47c390SBjoern A. Zeeb return (EINVAL); 120788768458SSam Leffler if (len < sizeof(*xpl)) 1208de47c390SBjoern A. Zeeb return (EINVAL); 120988768458SSam Leffler xpl = (struct sadb_x_policy *)request; 121088768458SSam Leffler 1211de47c390SBjoern A. Zeeb /* Select direction. */ 121288768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 121388768458SSam Leffler case IPSEC_DIR_INBOUND: 121428097b18SBjoern A. Zeeb pcb_sp = &inp->inp_sp->sp_in; 121588768458SSam Leffler break; 121688768458SSam Leffler case IPSEC_DIR_OUTBOUND: 121728097b18SBjoern A. Zeeb pcb_sp = &inp->inp_sp->sp_out; 121888768458SSam Leffler break; 121988768458SSam Leffler default: 12209ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 122188768458SSam Leffler xpl->sadb_x_policy_dir)); 1222de47c390SBjoern A. Zeeb return (EINVAL); 122388768458SSam Leffler } 122488768458SSam Leffler 1225de47c390SBjoern A. Zeeb return (ipsec_set_policy(pcb_sp, optname, request, len, cred)); 122688768458SSam Leffler } 122788768458SSam Leffler 122888768458SSam Leffler int 1229cd1a38f5SBjoern A. Zeeb ipsec6_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1230cd1a38f5SBjoern A. Zeeb struct mbuf **mp) 123188768458SSam Leffler { 12328b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 123388768458SSam Leffler struct sadb_x_policy *xpl; 123488768458SSam Leffler struct secpolicy *pcb_sp; 123588768458SSam Leffler 1236de47c390SBjoern A. Zeeb /* Sanity check. */ 123728097b18SBjoern A. Zeeb if (inp == NULL || request == NULL || mp == NULL) 1238de47c390SBjoern A. Zeeb return (EINVAL); 123928097b18SBjoern A. Zeeb IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 124088768458SSam Leffler if (len < sizeof(*xpl)) 1241de47c390SBjoern A. Zeeb return (EINVAL); 124288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 124388768458SSam Leffler 1244de47c390SBjoern A. Zeeb /* Select direction. */ 124588768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 124688768458SSam Leffler case IPSEC_DIR_INBOUND: 124728097b18SBjoern A. Zeeb pcb_sp = inp->inp_sp->sp_in; 124888768458SSam Leffler break; 124988768458SSam Leffler case IPSEC_DIR_OUTBOUND: 125028097b18SBjoern A. Zeeb pcb_sp = inp->inp_sp->sp_out; 125188768458SSam Leffler break; 125288768458SSam Leffler default: 12539ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 125488768458SSam Leffler xpl->sadb_x_policy_dir)); 1255de47c390SBjoern A. Zeeb return (EINVAL); 125688768458SSam Leffler } 125788768458SSam Leffler 1258de47c390SBjoern A. Zeeb return (ipsec_get_policy(pcb_sp, mp)); 125988768458SSam Leffler } 126088768458SSam Leffler #endif 126188768458SSam Leffler 126288768458SSam Leffler /* 1263de47c390SBjoern A. Zeeb * Return current level. 126488768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 126588768458SSam Leffler */ 126688768458SSam Leffler u_int 1267cd1a38f5SBjoern A. Zeeb ipsec_get_reqlevel(struct ipsecrequest *isr) 126888768458SSam Leffler { 12698b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 127088768458SSam Leffler u_int level = 0; 127188768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 127288768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 127388768458SSam Leffler 12749ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); 12759ffa9677SSam Leffler IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, 12769ffa9677SSam Leffler ("af family mismatch, src %u, dst %u", 127788768458SSam Leffler isr->sp->spidx.src.sa.sa_family, 127888768458SSam Leffler isr->sp->spidx.dst.sa.sa_family)); 127988768458SSam Leffler 1280de47c390SBjoern A. Zeeb /* XXX Note that we have ipseclog() expanded here - code sync issue. */ 128188768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 128288768458SSam Leffler (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ 128388768458SSam Leffler && (lev) != IPSEC_LEVEL_UNIQUE) \ 1284603724d3SBjoern A. Zeeb ? (V_ipsec_debug \ 128588768458SSam Leffler ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 128688768458SSam Leffler (lev), IPSEC_LEVEL_REQUIRE) \ 128788768458SSam Leffler : 0), \ 128888768458SSam Leffler (lev) = IPSEC_LEVEL_REQUIRE, \ 128988768458SSam Leffler (lev) \ 129088768458SSam Leffler : (lev)) 129188768458SSam Leffler 1292de47c390SBjoern A. Zeeb /* Set default level. */ 129388768458SSam Leffler switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { 129488768458SSam Leffler #ifdef INET 129588768458SSam Leffler case AF_INET: 1296603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 1297603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 1298603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 1299603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 130088768458SSam Leffler break; 130188768458SSam Leffler #endif 130288768458SSam Leffler #ifdef INET6 130388768458SSam Leffler case AF_INET6: 1304603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 1305603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 1306603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 1307603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 130888768458SSam Leffler break; 130988768458SSam Leffler #endif /* INET6 */ 131088768458SSam Leffler default: 13119ffa9677SSam Leffler panic("%s: unknown af %u", 13129ffa9677SSam Leffler __func__, isr->sp->spidx.src.sa.sa_family); 131388768458SSam Leffler } 131488768458SSam Leffler 131588768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 131688768458SSam Leffler 1317de47c390SBjoern A. Zeeb /* Set level. */ 131888768458SSam Leffler switch (isr->level) { 131988768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 132088768458SSam Leffler switch (isr->saidx.proto) { 132188768458SSam Leffler case IPPROTO_ESP: 132288768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 132388768458SSam Leffler level = esp_net_deflev; 132488768458SSam Leffler else 132588768458SSam Leffler level = esp_trans_deflev; 132688768458SSam Leffler break; 132788768458SSam Leffler case IPPROTO_AH: 132888768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 132988768458SSam Leffler level = ah_net_deflev; 133088768458SSam Leffler else 133188768458SSam Leffler level = ah_trans_deflev; 13328381996eSSam Leffler break; 133388768458SSam Leffler case IPPROTO_IPCOMP: 133488768458SSam Leffler /* 1335de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document says that 1336de47c390SBjoern A. Zeeb * we shouldn't compress small packets. 133788768458SSam Leffler */ 133888768458SSam Leffler level = IPSEC_LEVEL_USE; 133988768458SSam Leffler break; 134088768458SSam Leffler default: 13419ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 134288768458SSam Leffler isr->saidx.proto); 134388768458SSam Leffler } 134488768458SSam Leffler break; 134588768458SSam Leffler 134688768458SSam Leffler case IPSEC_LEVEL_USE: 134788768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 134888768458SSam Leffler level = isr->level; 134988768458SSam Leffler break; 135088768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 135188768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 135288768458SSam Leffler break; 135388768458SSam Leffler 135488768458SSam Leffler default: 13559ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 135688768458SSam Leffler } 135788768458SSam Leffler 1358de47c390SBjoern A. Zeeb return (level); 135988768458SSam Leffler } 136088768458SSam Leffler 136188768458SSam Leffler /* 136288768458SSam Leffler * Check security policy requirements against the actual 136388768458SSam Leffler * packet contents. Return one if the packet should be 136488768458SSam Leffler * reject as "invalid"; otherwiser return zero to have the 136588768458SSam Leffler * packet treated as "valid". 136688768458SSam Leffler * 136788768458SSam Leffler * OUT: 136888768458SSam Leffler * 0: valid 136988768458SSam Leffler * 1: invalid 137088768458SSam Leffler */ 137188768458SSam Leffler int 137288768458SSam Leffler ipsec_in_reject(struct secpolicy *sp, struct mbuf *m) 137388768458SSam Leffler { 13748b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 137588768458SSam Leffler struct ipsecrequest *isr; 137688768458SSam Leffler int need_auth; 137788768458SSam Leffler 137888768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 13799ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 138088768458SSam Leffler 1381de47c390SBjoern A. Zeeb /* Check policy. */ 138288768458SSam Leffler switch (sp->policy) { 138388768458SSam Leffler case IPSEC_POLICY_DISCARD: 1384de47c390SBjoern A. Zeeb return (1); 138588768458SSam Leffler case IPSEC_POLICY_BYPASS: 138688768458SSam Leffler case IPSEC_POLICY_NONE: 1387de47c390SBjoern A. Zeeb return (0); 138888768458SSam Leffler } 138988768458SSam Leffler 13909ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 13919ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 139288768458SSam Leffler 1393de47c390SBjoern A. Zeeb /* XXX Should compare policy against IPsec header history. */ 139488768458SSam Leffler 139588768458SSam Leffler need_auth = 0; 139688768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 139788768458SSam Leffler if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) 139888768458SSam Leffler continue; 139988768458SSam Leffler switch (isr->saidx.proto) { 140088768458SSam Leffler case IPPROTO_ESP: 140188768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 140288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14039ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 140488768458SSam Leffler m->m_flags)); 1405de47c390SBjoern A. Zeeb return (1); 140688768458SSam Leffler } 140788768458SSam Leffler 140888768458SSam Leffler if (!need_auth && 140988768458SSam Leffler isr->sav != NULL && 141088768458SSam Leffler isr->sav->tdb_authalgxform != NULL && 141188768458SSam Leffler (m->m_flags & M_AUTHIPDGM) == 0) { 141288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14139ffa9677SSam Leffler printf("%s: ESP/AH m_flags:%x\n", __func__, 141488768458SSam Leffler m->m_flags)); 1415de47c390SBjoern A. Zeeb return (1); 141688768458SSam Leffler } 141788768458SSam Leffler break; 141888768458SSam Leffler case IPPROTO_AH: 141988768458SSam Leffler need_auth = 1; 142088768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 142188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14229ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 142388768458SSam Leffler m->m_flags)); 1424de47c390SBjoern A. Zeeb return (1); 142588768458SSam Leffler } 142688768458SSam Leffler break; 142788768458SSam Leffler case IPPROTO_IPCOMP: 142888768458SSam Leffler /* 1429de47c390SBjoern A. Zeeb * We don't really care, as IPcomp document 143088768458SSam Leffler * says that we shouldn't compress small 1431de47c390SBjoern A. Zeeb * packets. IPComp policy should always be 143288768458SSam Leffler * treated as being in "use" level. 143388768458SSam Leffler */ 143488768458SSam Leffler break; 143588768458SSam Leffler } 143688768458SSam Leffler } 1437de47c390SBjoern A. Zeeb return (0); /* Valid. */ 143888768458SSam Leffler } 143988768458SSam Leffler 144088768458SSam Leffler /* 144188768458SSam Leffler * Check AH/ESP integrity. 144288768458SSam Leffler * This function is called from tcp_input(), udp_input(), 1443de47c390SBjoern A. Zeeb * and {ah,esp}4_input for tunnel mode. 144488768458SSam Leffler */ 144588768458SSam Leffler int 1446cd1a38f5SBjoern A. Zeeb ipsec4_in_reject(struct mbuf *m, struct inpcb *inp) 144788768458SSam Leffler { 14488b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 144988768458SSam Leffler struct secpolicy *sp; 145088768458SSam Leffler int error; 145188768458SSam Leffler int result; 145288768458SSam Leffler 14539ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 145488768458SSam Leffler 1455de47c390SBjoern A. Zeeb /* 1456de47c390SBjoern A. Zeeb * Get SP for this packet. 145788768458SSam Leffler * When we are called from ip_forward(), we call 145888768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 145988768458SSam Leffler */ 146088768458SSam Leffler if (inp == NULL) 146188768458SSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 146288768458SSam Leffler else 146388768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 146488768458SSam Leffler 146588768458SSam Leffler if (sp != NULL) { 146688768458SSam Leffler result = ipsec_in_reject(sp, m); 146788768458SSam Leffler if (result) 1468603724d3SBjoern A. Zeeb V_ipsec4stat.ips_in_polvio++; 146988768458SSam Leffler KEY_FREESP(&sp); 147088768458SSam Leffler } else { 1471de47c390SBjoern A. Zeeb result = 0; /* XXX Should be panic? 147288768458SSam Leffler * -> No, there may be error. */ 147388768458SSam Leffler } 1474de47c390SBjoern A. Zeeb return (result); 147588768458SSam Leffler } 147688768458SSam Leffler 147788768458SSam Leffler #ifdef INET6 147888768458SSam Leffler /* 147988768458SSam Leffler * Check AH/ESP integrity. 148088768458SSam Leffler * This function is called from tcp6_input(), udp6_input(), 1481de47c390SBjoern A. Zeeb * and {ah,esp}6_input for tunnel mode. 148288768458SSam Leffler */ 148388768458SSam Leffler int 1484cd1a38f5SBjoern A. Zeeb ipsec6_in_reject(struct mbuf *m, struct inpcb *inp) 148588768458SSam Leffler { 14868b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 148788768458SSam Leffler struct secpolicy *sp = NULL; 148888768458SSam Leffler int error; 148988768458SSam Leffler int result; 149088768458SSam Leffler 1491de47c390SBjoern A. Zeeb /* Sanity check. */ 149288768458SSam Leffler if (m == NULL) 1493de47c390SBjoern A. Zeeb return (0); /* XXX Should be panic? */ 149488768458SSam Leffler 1495de47c390SBjoern A. Zeeb /* Get SP for this packet. 149688768458SSam Leffler * When we are called from ip_forward(), we call 149788768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 149888768458SSam Leffler */ 149988768458SSam Leffler if (inp == NULL) 150088768458SSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 150188768458SSam Leffler else 150288768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 150388768458SSam Leffler 150488768458SSam Leffler if (sp != NULL) { 150588768458SSam Leffler result = ipsec_in_reject(sp, m); 150688768458SSam Leffler if (result) 1507603724d3SBjoern A. Zeeb V_ipsec6stat.ips_in_polvio++; 150888768458SSam Leffler KEY_FREESP(&sp); 150988768458SSam Leffler } else { 151088768458SSam Leffler result = 0; 151188768458SSam Leffler } 1512de47c390SBjoern A. Zeeb return (result); 151388768458SSam Leffler } 151488768458SSam Leffler #endif 151588768458SSam Leffler 151688768458SSam Leffler /* 1517de47c390SBjoern A. Zeeb * Compute the byte size to be occupied by IPsec header. 1518de47c390SBjoern A. Zeeb * In case it is tunnelled, it includes the size of outer IP header. 1519de47c390SBjoern A. Zeeb * NOTE: SP passed is freed in this function. 152088768458SSam Leffler */ 152188768458SSam Leffler static size_t 152288768458SSam Leffler ipsec_hdrsiz(struct secpolicy *sp) 152388768458SSam Leffler { 15248b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 152588768458SSam Leffler struct ipsecrequest *isr; 152688768458SSam Leffler size_t siz; 152788768458SSam Leffler 152888768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 15299ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 153088768458SSam Leffler 153188768458SSam Leffler switch (sp->policy) { 153288768458SSam Leffler case IPSEC_POLICY_DISCARD: 153388768458SSam Leffler case IPSEC_POLICY_BYPASS: 153488768458SSam Leffler case IPSEC_POLICY_NONE: 1535de47c390SBjoern A. Zeeb return (0); 153688768458SSam Leffler } 153788768458SSam Leffler 15389ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 15399ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 154088768458SSam Leffler 154188768458SSam Leffler siz = 0; 154288768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 154388768458SSam Leffler size_t clen = 0; 154488768458SSam Leffler 154588768458SSam Leffler switch (isr->saidx.proto) { 154688768458SSam Leffler case IPPROTO_ESP: 154788768458SSam Leffler clen = esp_hdrsiz(isr->sav); 154888768458SSam Leffler break; 154988768458SSam Leffler case IPPROTO_AH: 155088768458SSam Leffler clen = ah_hdrsiz(isr->sav); 155188768458SSam Leffler break; 155288768458SSam Leffler case IPPROTO_IPCOMP: 155388768458SSam Leffler clen = sizeof(struct ipcomp); 155488768458SSam Leffler break; 155588768458SSam Leffler } 155688768458SSam Leffler 155788768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 155888768458SSam Leffler switch (isr->saidx.dst.sa.sa_family) { 155988768458SSam Leffler case AF_INET: 156088768458SSam Leffler clen += sizeof(struct ip); 156188768458SSam Leffler break; 156288768458SSam Leffler #ifdef INET6 156388768458SSam Leffler case AF_INET6: 156488768458SSam Leffler clen += sizeof(struct ip6_hdr); 156588768458SSam Leffler break; 156688768458SSam Leffler #endif 156788768458SSam Leffler default: 15689ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 15699ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 157088768458SSam Leffler ((struct sockaddr *)&isr->saidx.dst)->sa_family)); 157188768458SSam Leffler break; 157288768458SSam Leffler } 157388768458SSam Leffler } 157488768458SSam Leffler siz += clen; 157588768458SSam Leffler } 157688768458SSam Leffler 1577de47c390SBjoern A. Zeeb return (siz); 157888768458SSam Leffler } 157988768458SSam Leffler 158088768458SSam Leffler /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ 158188768458SSam Leffler size_t 1582cd1a38f5SBjoern A. Zeeb ipsec4_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) 158388768458SSam Leffler { 15848b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 158588768458SSam Leffler struct secpolicy *sp; 158688768458SSam Leffler int error; 158788768458SSam Leffler size_t size; 158888768458SSam Leffler 15899ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 159088768458SSam Leffler 1591de47c390SBjoern A. Zeeb /* Get SP for this packet. 159288768458SSam Leffler * When we are called from ip_forward(), we call 159388768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 159488768458SSam Leffler */ 159588768458SSam Leffler if (inp == NULL) 159688768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 159788768458SSam Leffler else 159888768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, &error); 159988768458SSam Leffler 160088768458SSam Leffler if (sp != NULL) { 160188768458SSam Leffler size = ipsec_hdrsiz(sp); 160288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 16039ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, 160488768458SSam Leffler (unsigned long)size)); 160588768458SSam Leffler 160688768458SSam Leffler KEY_FREESP(&sp); 160788768458SSam Leffler } else { 1608de47c390SBjoern A. Zeeb size = 0; /* XXX Should be panic? 16094a67e051SBjoern A. Zeeb * -> No, we are called w/o knowing if 16104a67e051SBjoern A. Zeeb * IPsec processing is needed. */ 161188768458SSam Leffler } 1612de47c390SBjoern A. Zeeb return (size); 161388768458SSam Leffler } 161488768458SSam Leffler 161588768458SSam Leffler #ifdef INET6 161688768458SSam Leffler /* This function is called from ipsec6_hdrsize_tcp(), 1617de47c390SBjoern A. Zeeb * and maybe from ip6_forward(). 161888768458SSam Leffler */ 161988768458SSam Leffler size_t 1620cd1a38f5SBjoern A. Zeeb ipsec6_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) 162188768458SSam Leffler { 16228b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 162388768458SSam Leffler struct secpolicy *sp; 162488768458SSam Leffler int error; 162588768458SSam Leffler size_t size; 162688768458SSam Leffler 16279ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 162828097b18SBjoern A. Zeeb IPSEC_ASSERT(inp == NULL || inp->inp_socket != NULL, 16299ffa9677SSam Leffler ("socket w/o inpcb")); 163088768458SSam Leffler 1631de47c390SBjoern A. Zeeb /* Get SP for this packet. */ 163288768458SSam Leffler /* XXX Is it right to call with IP_FORWARDING. */ 163328097b18SBjoern A. Zeeb if (inp == NULL) 163488768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 163588768458SSam Leffler else 163628097b18SBjoern A. Zeeb sp = ipsec_getpolicybysock(m, dir, inp, &error); 163788768458SSam Leffler 163888768458SSam Leffler if (sp == NULL) 1639de47c390SBjoern A. Zeeb return (0); 164088768458SSam Leffler size = ipsec_hdrsiz(sp); 164188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 16429ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, (unsigned long)size)); 164388768458SSam Leffler KEY_FREESP(&sp); 164488768458SSam Leffler 1645de47c390SBjoern A. Zeeb return (size); 164688768458SSam Leffler } 164788768458SSam Leffler #endif /*INET6*/ 164888768458SSam Leffler 164988768458SSam Leffler /* 165088768458SSam Leffler * Check the variable replay window. 165188768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 165288768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 165388768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 165488768458SSam Leffler * beforehand). 165588768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 165688768458SSam Leffler * 1657de47c390SBjoern A. Zeeb * Based on RFC 2401. 165888768458SSam Leffler */ 165988768458SSam Leffler int 1660cd1a38f5SBjoern A. Zeeb ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) 166188768458SSam Leffler { 166288768458SSam Leffler const struct secreplay *replay; 166388768458SSam Leffler u_int32_t diff; 166488768458SSam Leffler int fr; 1665de47c390SBjoern A. Zeeb u_int32_t wsizeb; /* Constant: bits of window size. */ 1666de47c390SBjoern A. Zeeb int frlast; /* Constant: last frame. */ 166788768458SSam Leffler 16689ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 16699ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 167088768458SSam Leffler 167188768458SSam Leffler replay = sav->replay; 167288768458SSam Leffler 167388768458SSam Leffler if (replay->wsize == 0) 1674de47c390SBjoern A. Zeeb return (1); /* No need to check replay. */ 167588768458SSam Leffler 1676de47c390SBjoern A. Zeeb /* Constant. */ 167788768458SSam Leffler frlast = replay->wsize - 1; 167888768458SSam Leffler wsizeb = replay->wsize << 3; 167988768458SSam Leffler 1680de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 168188768458SSam Leffler if (seq == 0) 1682de47c390SBjoern A. Zeeb return (0); 168388768458SSam Leffler 1684de47c390SBjoern A. Zeeb /* First time is always okay. */ 168588768458SSam Leffler if (replay->count == 0) 1686de47c390SBjoern A. Zeeb return (1); 168788768458SSam Leffler 168888768458SSam Leffler if (seq > replay->lastseq) { 1689de47c390SBjoern A. Zeeb /* Larger sequences are okay. */ 1690de47c390SBjoern A. Zeeb return (1); 169188768458SSam Leffler } else { 169288768458SSam Leffler /* seq is equal or less than lastseq. */ 169388768458SSam Leffler diff = replay->lastseq - seq; 169488768458SSam Leffler 1695de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 169688768458SSam Leffler if (diff >= wsizeb) 1697de47c390SBjoern A. Zeeb return (0); 169888768458SSam Leffler 169988768458SSam Leffler fr = frlast - diff / 8; 170088768458SSam Leffler 1701de47c390SBjoern A. Zeeb /* This packet already seen? */ 170288768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1703de47c390SBjoern A. Zeeb return (0); 170488768458SSam Leffler 1705de47c390SBjoern A. Zeeb /* Out of order but good. */ 1706de47c390SBjoern A. Zeeb return (1); 170788768458SSam Leffler } 170888768458SSam Leffler } 170988768458SSam Leffler 171088768458SSam Leffler /* 1711de47c390SBjoern A. Zeeb * Check replay counter whether to update or not. 171288768458SSam Leffler * OUT: 0: OK 171388768458SSam Leffler * 1: NG 171488768458SSam Leffler */ 171588768458SSam Leffler int 1716cd1a38f5SBjoern A. Zeeb ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) 171788768458SSam Leffler { 17188b615593SMarko Zec INIT_VNET_IPSEC(curvnet); 171988768458SSam Leffler struct secreplay *replay; 172088768458SSam Leffler u_int32_t diff; 172188768458SSam Leffler int fr; 1722de47c390SBjoern A. Zeeb u_int32_t wsizeb; /* Constant: bits of window size. */ 1723de47c390SBjoern A. Zeeb int frlast; /* Constant: last frame. */ 172488768458SSam Leffler 17259ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 17269ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 172788768458SSam Leffler 172888768458SSam Leffler replay = sav->replay; 172988768458SSam Leffler 173088768458SSam Leffler if (replay->wsize == 0) 1731de47c390SBjoern A. Zeeb goto ok; /* No need to check replay. */ 173288768458SSam Leffler 1733de47c390SBjoern A. Zeeb /* Constant. */ 173488768458SSam Leffler frlast = replay->wsize - 1; 173588768458SSam Leffler wsizeb = replay->wsize << 3; 173688768458SSam Leffler 1737de47c390SBjoern A. Zeeb /* Sequence number of 0 is invalid. */ 173888768458SSam Leffler if (seq == 0) 1739de47c390SBjoern A. Zeeb return (1); 174088768458SSam Leffler 1741de47c390SBjoern A. Zeeb /* First time. */ 174288768458SSam Leffler if (replay->count == 0) { 174388768458SSam Leffler replay->lastseq = seq; 174488768458SSam Leffler bzero(replay->bitmap, replay->wsize); 174588768458SSam Leffler (replay->bitmap)[frlast] = 1; 174688768458SSam Leffler goto ok; 174788768458SSam Leffler } 174888768458SSam Leffler 174988768458SSam Leffler if (seq > replay->lastseq) { 175088768458SSam Leffler /* seq is larger than lastseq. */ 175188768458SSam Leffler diff = seq - replay->lastseq; 175288768458SSam Leffler 1753de47c390SBjoern A. Zeeb /* New larger sequence number. */ 175488768458SSam Leffler if (diff < wsizeb) { 1755de47c390SBjoern A. Zeeb /* In window. */ 1756de47c390SBjoern A. Zeeb /* Set bit for this packet. */ 175788768458SSam Leffler vshiftl(replay->bitmap, diff, replay->wsize); 175888768458SSam Leffler (replay->bitmap)[frlast] |= 1; 175988768458SSam Leffler } else { 1760de47c390SBjoern A. Zeeb /* This packet has a "way larger". */ 176188768458SSam Leffler bzero(replay->bitmap, replay->wsize); 176288768458SSam Leffler (replay->bitmap)[frlast] = 1; 176388768458SSam Leffler } 176488768458SSam Leffler replay->lastseq = seq; 176588768458SSam Leffler 1766de47c390SBjoern A. Zeeb /* Larger is good. */ 176788768458SSam Leffler } else { 176888768458SSam Leffler /* seq is equal or less than lastseq. */ 176988768458SSam Leffler diff = replay->lastseq - seq; 177088768458SSam Leffler 1771de47c390SBjoern A. Zeeb /* Over range to check, i.e. too old or wrapped. */ 177288768458SSam Leffler if (diff >= wsizeb) 1773de47c390SBjoern A. Zeeb return (1); 177488768458SSam Leffler 177588768458SSam Leffler fr = frlast - diff / 8; 177688768458SSam Leffler 1777de47c390SBjoern A. Zeeb /* This packet already seen? */ 177888768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1779de47c390SBjoern A. Zeeb return (1); 178088768458SSam Leffler 1781de47c390SBjoern A. Zeeb /* Mark as seen. */ 178288768458SSam Leffler (replay->bitmap)[fr] |= (1 << (diff % 8)); 178388768458SSam Leffler 1784de47c390SBjoern A. Zeeb /* Out of order but good. */ 178588768458SSam Leffler } 178688768458SSam Leffler 178788768458SSam Leffler ok: 178888768458SSam Leffler if (replay->count == ~0) { 178988768458SSam Leffler 1790de47c390SBjoern A. Zeeb /* Set overflow flag. */ 179188768458SSam Leffler replay->overflow++; 179288768458SSam Leffler 1793de47c390SBjoern A. Zeeb /* Don't increment, no more packets accepted. */ 179488768458SSam Leffler if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) 1795de47c390SBjoern A. Zeeb return (1); 179688768458SSam Leffler 17979ffa9677SSam Leffler ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 17989ffa9677SSam Leffler __func__, replay->overflow, ipsec_logsastr(sav))); 179988768458SSam Leffler } 180088768458SSam Leffler 180188768458SSam Leffler replay->count++; 180288768458SSam Leffler 1803de47c390SBjoern A. Zeeb return (0); 180488768458SSam Leffler } 180588768458SSam Leffler 180688768458SSam Leffler /* 1807de47c390SBjoern A. Zeeb * Shift variable length buffer to left. 180888768458SSam Leffler * IN: bitmap: pointer to the buffer 180988768458SSam Leffler * nbit: the number of to shift. 181088768458SSam Leffler * wsize: buffer size (bytes). 181188768458SSam Leffler */ 181288768458SSam Leffler static void 1813cd1a38f5SBjoern A. Zeeb vshiftl(unsigned char *bitmap, int nbit, int wsize) 181488768458SSam Leffler { 181588768458SSam Leffler int s, j, i; 181688768458SSam Leffler unsigned char over; 181788768458SSam Leffler 181888768458SSam Leffler for (j = 0; j < nbit; j += 8) { 181988768458SSam Leffler s = (nbit - j < 8) ? (nbit - j): 8; 182088768458SSam Leffler bitmap[0] <<= s; 182188768458SSam Leffler for (i = 1; i < wsize; i++) { 182288768458SSam Leffler over = (bitmap[i] >> (8 - s)); 182388768458SSam Leffler bitmap[i] <<= s; 182488768458SSam Leffler bitmap[i-1] |= over; 182588768458SSam Leffler } 182688768458SSam Leffler } 182788768458SSam Leffler } 182888768458SSam Leffler 182988768458SSam Leffler /* Return a printable string for the IPv4 address. */ 183088768458SSam Leffler static char * 183188768458SSam Leffler inet_ntoa4(struct in_addr ina) 183288768458SSam Leffler { 183388768458SSam Leffler static char buf[4][4 * sizeof "123" + 4]; 183488768458SSam Leffler unsigned char *ucp = (unsigned char *) &ina; 183588768458SSam Leffler static int i = 3; 183688768458SSam Leffler 1837de47c390SBjoern A. Zeeb /* XXX-BZ Returns static buffer. */ 183888768458SSam Leffler i = (i + 1) % 4; 183988768458SSam Leffler sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, 184088768458SSam Leffler ucp[2] & 0xff, ucp[3] & 0xff); 184188768458SSam Leffler return (buf[i]); 184288768458SSam Leffler } 184388768458SSam Leffler 184488768458SSam Leffler /* Return a printable string for the address. */ 184588768458SSam Leffler char * 184688768458SSam Leffler ipsec_address(union sockaddr_union* sa) 184788768458SSam Leffler { 1848224c45c4SBjoern A. Zeeb #ifdef INET6 18491d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 18501d54aa3bSBjoern A. Zeeb #endif 1851de47c390SBjoern A. Zeeb 185288768458SSam Leffler switch (sa->sa.sa_family) { 185349ddabdfSPawel Jakub Dawidek #ifdef INET 185488768458SSam Leffler case AF_INET: 1855de47c390SBjoern A. Zeeb return (inet_ntoa4(sa->sin.sin_addr)); 185688768458SSam Leffler #endif /* INET */ 185749ddabdfSPawel Jakub Dawidek #ifdef INET6 185888768458SSam Leffler case AF_INET6: 1859de47c390SBjoern A. Zeeb return (ip6_sprintf(ip6buf, &sa->sin6.sin6_addr)); 186088768458SSam Leffler #endif /* INET6 */ 186188768458SSam Leffler default: 1862de47c390SBjoern A. Zeeb return ("(unknown address family)"); 186388768458SSam Leffler } 186488768458SSam Leffler } 186588768458SSam Leffler 186688768458SSam Leffler const char * 1867cd1a38f5SBjoern A. Zeeb ipsec_logsastr(struct secasvar *sav) 186888768458SSam Leffler { 186988768458SSam Leffler static char buf[256]; 187088768458SSam Leffler char *p; 187188768458SSam Leffler struct secasindex *saidx = &sav->sah->saidx; 187288768458SSam Leffler 18739ffa9677SSam Leffler IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, 18749ffa9677SSam Leffler ("address family mismatch")); 187588768458SSam Leffler 187688768458SSam Leffler p = buf; 187788768458SSam Leffler snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); 187888768458SSam Leffler while (p && *p) 187988768458SSam Leffler p++; 1880de47c390SBjoern A. Zeeb /* NB: only use ipsec_address on one address at a time. */ 188188768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "src=%s ", 188288768458SSam Leffler ipsec_address(&saidx->src)); 188388768458SSam Leffler while (p && *p) 188488768458SSam Leffler p++; 188588768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", 188688768458SSam Leffler ipsec_address(&saidx->dst)); 188788768458SSam Leffler 1888de47c390SBjoern A. Zeeb return (buf); 188988768458SSam Leffler } 189088768458SSam Leffler 189188768458SSam Leffler void 1892cd1a38f5SBjoern A. Zeeb ipsec_dumpmbuf(struct mbuf *m) 189388768458SSam Leffler { 189488768458SSam Leffler int totlen; 189588768458SSam Leffler int i; 189688768458SSam Leffler u_char *p; 189788768458SSam Leffler 189888768458SSam Leffler totlen = 0; 189988768458SSam Leffler printf("---\n"); 190088768458SSam Leffler while (m) { 190188768458SSam Leffler p = mtod(m, u_char *); 190288768458SSam Leffler for (i = 0; i < m->m_len; i++) { 190388768458SSam Leffler printf("%02x ", p[i]); 190488768458SSam Leffler totlen++; 190588768458SSam Leffler if (totlen % 16 == 0) 190688768458SSam Leffler printf("\n"); 190788768458SSam Leffler } 190888768458SSam Leffler m = m->m_next; 190988768458SSam Leffler } 191088768458SSam Leffler if (totlen % 16 != 0) 191188768458SSam Leffler printf("\n"); 191288768458SSam Leffler printf("---\n"); 191388768458SSam Leffler } 191488768458SSam Leffler 19158381996eSSam Leffler static void 19168381996eSSam Leffler ipsec_attach(void) 19178381996eSSam Leffler { 1918de47c390SBjoern A. Zeeb 1919603724d3SBjoern A. Zeeb SECPOLICY_LOCK_INIT(&V_ip4_def_policy); 1920de47c390SBjoern A. Zeeb V_ip4_def_policy.refcnt = 1; /* NB: disallow free. */ 19218381996eSSam Leffler } 1922237fdd78SRobert Watson SYSINIT(ipsec, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, ipsec_attach, NULL); 19238381996eSSam Leffler 19248381996eSSam Leffler 1925de47c390SBjoern A. Zeeb /* XXX This stuff doesn't belong here... */ 192688768458SSam Leffler 192788768458SSam Leffler static struct xformsw* xforms = NULL; 192888768458SSam Leffler 192988768458SSam Leffler /* 193088768458SSam Leffler * Register a transform; typically at system startup. 193188768458SSam Leffler */ 193288768458SSam Leffler void 193388768458SSam Leffler xform_register(struct xformsw* xsp) 193488768458SSam Leffler { 1935de47c390SBjoern A. Zeeb 193688768458SSam Leffler xsp->xf_next = xforms; 193788768458SSam Leffler xforms = xsp; 193888768458SSam Leffler } 193988768458SSam Leffler 194088768458SSam Leffler /* 194188768458SSam Leffler * Initialize transform support in an sav. 194288768458SSam Leffler */ 194388768458SSam Leffler int 194488768458SSam Leffler xform_init(struct secasvar *sav, int xftype) 194588768458SSam Leffler { 194688768458SSam Leffler struct xformsw *xsp; 194788768458SSam Leffler 1948de47c390SBjoern A. Zeeb if (sav->tdb_xform != NULL) /* Previously initialized. */ 1949de47c390SBjoern A. Zeeb return (0); 195088768458SSam Leffler for (xsp = xforms; xsp; xsp = xsp->xf_next) 195188768458SSam Leffler if (xsp->xf_type == xftype) 1952de47c390SBjoern A. Zeeb return ((*xsp->xf_init)(sav, xsp)); 1953de47c390SBjoern A. Zeeb return (EINVAL); 195488768458SSam Leffler } 1955