ipsec.c revision 186530
1105197Ssam/* $FreeBSD: head/sys/netipsec/ipsec.c 186530 2008-12-27 21:20:34Z bz $ */ 2105197Ssam/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ 3105197Ssam 4139823Simp/*- 5105197Ssam * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6105197Ssam * All rights reserved. 7105197Ssam * 8105197Ssam * Redistribution and use in source and binary forms, with or without 9105197Ssam * modification, are permitted provided that the following conditions 10105197Ssam * are met: 11105197Ssam * 1. Redistributions of source code must retain the above copyright 12105197Ssam * notice, this list of conditions and the following disclaimer. 13105197Ssam * 2. Redistributions in binary form must reproduce the above copyright 14105197Ssam * notice, this list of conditions and the following disclaimer in the 15105197Ssam * documentation and/or other materials provided with the distribution. 16105197Ssam * 3. Neither the name of the project nor the names of its contributors 17105197Ssam * may be used to endorse or promote products derived from this software 18105197Ssam * without specific prior written permission. 19105197Ssam * 20105197Ssam * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21105197Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22105197Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23105197Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24105197Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25105197Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26105197Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27105197Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28105197Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29105197Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30105197Ssam * SUCH DAMAGE. 31105197Ssam */ 32105197Ssam 33105197Ssam/* 34105197Ssam * IPsec controller part. 35105197Ssam */ 36105197Ssam 37105197Ssam#include "opt_inet.h" 38105197Ssam#include "opt_inet6.h" 39105197Ssam#include "opt_ipsec.h" 40105197Ssam 41105197Ssam#include <sys/param.h> 42105197Ssam#include <sys/systm.h> 43105197Ssam#include <sys/malloc.h> 44105197Ssam#include <sys/mbuf.h> 45105197Ssam#include <sys/domain.h> 46164056Srwatson#include <sys/priv.h> 47105197Ssam#include <sys/protosw.h> 48105197Ssam#include <sys/socket.h> 49105197Ssam#include <sys/socketvar.h> 50105197Ssam#include <sys/errno.h> 51105197Ssam#include <sys/time.h> 52105197Ssam#include <sys/kernel.h> 53105197Ssam#include <sys/syslog.h> 54105197Ssam#include <sys/sysctl.h> 55105197Ssam#include <sys/proc.h> 56181803Sbz#include <sys/vimage.h> 57105197Ssam 58105197Ssam#include <net/if.h> 59105197Ssam#include <net/route.h> 60105197Ssam 61105197Ssam#include <netinet/in.h> 62105197Ssam#include <netinet/in_systm.h> 63105197Ssam#include <netinet/ip.h> 64105197Ssam#include <netinet/ip_var.h> 65105197Ssam#include <netinet/in_var.h> 66105197Ssam#include <netinet/udp.h> 67105197Ssam#include <netinet/udp_var.h> 68105197Ssam#include <netinet/tcp.h> 69105197Ssam#include <netinet/udp.h> 70105197Ssam 71105197Ssam#include <netinet/ip6.h> 72105197Ssam#ifdef INET6 73105197Ssam#include <netinet6/ip6_var.h> 74105197Ssam#endif 75105197Ssam#include <netinet/in_pcb.h> 76105197Ssam#ifdef INET6 77105197Ssam#include <netinet/icmp6.h> 78105197Ssam#endif 79105197Ssam 80171133Sgnn#include <sys/types.h> 81105197Ssam#include <netipsec/ipsec.h> 82105197Ssam#ifdef INET6 83105197Ssam#include <netipsec/ipsec6.h> 84105197Ssam#endif 85105197Ssam#include <netipsec/ah_var.h> 86105197Ssam#include <netipsec/esp_var.h> 87105197Ssam#include <netipsec/ipcomp.h> /*XXX*/ 88105197Ssam#include <netipsec/ipcomp_var.h> 89105197Ssam 90105197Ssam#include <netipsec/key.h> 91105197Ssam#include <netipsec/keydb.h> 92105197Ssam#include <netipsec/key_debug.h> 93105197Ssam 94105197Ssam#include <netipsec/xform.h> 95105197Ssam 96105197Ssam#include <machine/in_cksum.h> 97105197Ssam 98167820Ssam#include <opencrypto/cryptodev.h> 99167820Ssam 100185895Szec#ifndef VIMAGE 101185895Szec#ifndef VIMAGE_GLOBALS 102185895Szecstruct vnet_ipsec vnet_ipsec_0; 103185895Szec#endif 104185895Szec#endif 105185895Szec 106185088Szec#ifdef VIMAGE_GLOBALS 107105197Ssam/* NB: name changed so netstat doesn't use it */ 108171133Sgnnstruct ipsecstat ipsec4stat; 109105197Ssamstruct secpolicy ip4_def_policy; 110185088Szecint ipsec_debug; 111185088Szecint ip4_ah_offsetmask; 112185088Szecint ip4_ipsec_dfbit; 113185088Szecint ip4_esp_trans_deflev; 114185088Szecint ip4_esp_net_deflev; 115185088Szecint ip4_ah_trans_deflev; 116185088Szecint ip4_ah_net_deflev; 117185088Szecint ip4_ipsec_ecn; 118185088Szecint ip4_esp_randpad; 119105197Ssam/* 120105197Ssam * Crypto support requirements: 121105197Ssam * 122105197Ssam * 1 require hardware support 123105197Ssam * -1 require software support 124105197Ssam * 0 take anything 125105197Ssam */ 126185088Szecint crypto_support; 127185088Szec#endif /* VIMAGE_GLOBALS */ 128105197Ssam 129105197SsamSYSCTL_DECL(_net_inet_ipsec); 130105197Ssam 131105197Ssam/* net.inet.ipsec */ 132183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_POLICY, 133183550Szec def_policy, CTLFLAG_RW, ip4_def_policy.policy, 0, 134183550Szec "IPsec default policy."); 135183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, 136183550Szec esp_trans_deflev, CTLFLAG_RW, ip4_esp_trans_deflev, 0, 137183550Szec "Default ESP transport mode level"); 138183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, 139183550Szec esp_net_deflev, CTLFLAG_RW, ip4_esp_net_deflev, 0, 140183550Szec "Default ESP tunnel mode level."); 141183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, 142183550Szec ah_trans_deflev, CTLFLAG_RW, ip4_ah_trans_deflev, 0, 143183550Szec "AH transfer mode default level."); 144183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, 145183550Szec ah_net_deflev, CTLFLAG_RW, ip4_ah_net_deflev, 0, 146183550Szec "AH tunnel mode default level."); 147183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_CLEARTOS, 148183550Szec ah_cleartos, CTLFLAG_RW, ah_cleartos, 0, 149183550Szec "If set clear type-of-service field when doing AH computation."); 150183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, 151183550Szec ah_offsetmask, CTLFLAG_RW, ip4_ah_offsetmask, 0, 152183550Szec "If not set clear offset field mask when doing AH computation."); 153183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DFBIT, 154183550Szec dfbit, CTLFLAG_RW, ip4_ipsec_dfbit, 0, 155183550Szec "Do not fragment bit on encap."); 156183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_ECN, 157183550Szec ecn, CTLFLAG_RW, ip4_ipsec_ecn, 0, 158183550Szec "Explicit Congestion Notification handling."); 159183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEBUG, 160183550Szec debug, CTLFLAG_RW, ipsec_debug, 0, 161183550Szec "Enable IPsec debugging output when set."); 162183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO, 163183550Szec crypto_support, CTLFLAG_RW, crypto_support,0, 164183550Szec "Crypto driver selection."); 165183550SzecSYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO, 166183550Szec ipsecstats, CTLFLAG_RD, ipsec4stat, ipsecstat, 167183550Szec "IPsec IPv4 statistics."); 168105197Ssam 169157634Spjd#ifdef REGRESSION 170185088Szec#ifdef VIMAGE_GLOBALS 171185088Szecint ipsec_replay; 172185088Szecint ipsec_integrity; 173185088Szec#endif 174157613Spjd/* 175157613Spjd * When set to 1, IPsec will send packets with the same sequence number. 176157613Spjd * This allows to verify if the other side has proper replay attacks detection. 177157613Spjd */ 178183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_replay, 179183550Szec CTLFLAG_RW, ipsec_replay, 0, "Emulate replay attack"); 180157613Spjd/* 181157613Spjd * When set 1, IPsec will send packets with corrupted HMAC. 182157613Spjd * This allows to verify if the other side properly detects modified packets. 183157613Spjd */ 184183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_integrity, 185183550Szec CTLFLAG_RW, ipsec_integrity, 0, "Emulate man-in-the-middle attack"); 186157634Spjd#endif 187157613Spjd 188171133Sgnn#ifdef INET6 189185088Szec#ifdef VIMAGE_GLOBALS 190171133Sgnnstruct ipsecstat ipsec6stat; 191185088Szecint ip6_esp_trans_deflev; 192185088Szecint ip6_esp_net_deflev; 193185088Szecint ip6_ah_trans_deflev; 194185088Szecint ip6_ah_net_deflev; 195185088Szecint ip6_ipsec_ecn; 196185088Szec#endif 197105197Ssam 198105197SsamSYSCTL_DECL(_net_inet6_ipsec6); 199105197Ssam 200105197Ssam/* net.inet6.ipsec6 */ 201105197Ssam#ifdef COMPAT_KAME 202105197SsamSYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, 203180820Strhodes 0, 0, compat_ipsecstats_sysctl, "S", "IPsec IPv6 statistics."); 204105197Ssam#endif /* COMPAT_KAME */ 205183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_POLICY, 206183550Szec def_policy, CTLFLAG_RW, ip4_def_policy.policy, 0, 207183550Szec "IPsec default policy."); 208183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, 209183550Szec esp_trans_deflev, CTLFLAG_RW, ip6_esp_trans_deflev, 0, 210183550Szec "Default ESP transport mode level."); 211183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, 212183550Szec esp_net_deflev, CTLFLAG_RW, ip6_esp_net_deflev, 0, 213183550Szec "Default ESP tunnel mode level."); 214183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, 215183550Szec ah_trans_deflev, CTLFLAG_RW, ip6_ah_trans_deflev, 0, 216183550Szec "AH transfer mode default level."); 217183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, 218183550Szec ah_net_deflev, CTLFLAG_RW, ip6_ah_net_deflev, 0, 219183550Szec "AH tunnel mode default level."); 220183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_ECN, 221183550Szec ecn, CTLFLAG_RW, ip6_ipsec_ecn, 0, 222183550Szec "Explicit Congestion Notification handling."); 223183550SzecSYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEBUG, 224183550Szec debug, CTLFLAG_RW, ipsec_debug, 0, 225183550Szec "Enable IPsec debugging output when set."); 226183550SzecSYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_STATS, 227183550Szec ipsecstats, CTLFLAG_RD, ipsec6stat, ipsecstat, 228183550Szec "IPsec IPv6 statistics."); 229105197Ssam#endif /* INET6 */ 230105197Ssam 231105197Ssamstatic int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); 232105197Ssam#ifdef INET6 233186527Sbzstatic int ipsec6_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); 234105197Ssam#endif 235105197Ssamstatic int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); 236105197Ssamstatic void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 237105197Ssamstatic int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 238105197Ssam#ifdef INET6 239105197Ssamstatic void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 240105197Ssamstatic int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 241105197Ssam#endif 242105197Ssamstatic void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); 243105197Ssamstatic struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); 244105197Ssamstatic int ipsec_set_policy __P((struct secpolicy **pcb_sp, 245175892Sbz int optname, caddr_t request, size_t len, struct ucred *cred)); 246105197Ssamstatic int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); 247105197Ssamstatic void vshiftl __P((unsigned char *, int, int)); 248105197Ssamstatic size_t ipsec_hdrsiz __P((struct secpolicy *)); 249105197Ssam 250119643SsamMALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); 251119643Ssam 252185088Szecvoid 253185088Szecipsec_init(void) 254185088Szec{ 255185088Szec INIT_VNET_IPSEC(curvnet); 256185088Szec 257185088Szec#ifdef IPSEC_DEBUG 258185088Szec V_ipsec_debug = 1; 259185088Szec#else 260185088Szec V_ipsec_debug = 0; 261185088Szec#endif 262185088Szec 263185088Szec V_ip4_ah_offsetmask = 0; /* maybe IP_DF? */ 264185088Szec V_ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ 265185088Szec V_ip4_esp_trans_deflev = IPSEC_LEVEL_USE; 266185088Szec V_ip4_esp_net_deflev = IPSEC_LEVEL_USE; 267185088Szec V_ip4_ah_trans_deflev = IPSEC_LEVEL_USE; 268185088Szec V_ip4_ah_net_deflev = IPSEC_LEVEL_USE; 269185088Szec V_ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 270185088Szec V_ip4_esp_randpad = -1; 271185088Szec 272185088Szec V_crypto_support = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 273185088Szec 274185088Szec#ifdef REGRESSION 275185088Szec V_ipsec_replay = 0; 276185088Szec V_ipsec_integrity = 0; 277185088Szec#endif 278185088Szec 279185292Sbz#ifdef INET6 280185088Szec V_ip6_esp_trans_deflev = IPSEC_LEVEL_USE; 281185088Szec V_ip6_esp_net_deflev = IPSEC_LEVEL_USE; 282185088Szec V_ip6_ah_trans_deflev = IPSEC_LEVEL_USE; 283185088Szec V_ip6_ah_net_deflev = IPSEC_LEVEL_USE; 284185088Szec V_ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 285185292Sbz#endif 286185088Szec} 287185088Szec 288105197Ssam/* 289105197Ssam * Return a held reference to the default SP. 290105197Ssam */ 291105197Ssamstatic struct secpolicy * 292105197Ssamkey_allocsp_default(const char* where, int tag) 293105197Ssam{ 294183550Szec INIT_VNET_IPSEC(curvnet); 295105197Ssam struct secpolicy *sp; 296105197Ssam 297105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 298105197Ssam printf("DP key_allocsp_default from %s:%u\n", where, tag)); 299105197Ssam 300181803Sbz sp = &V_ip4_def_policy; 301105197Ssam if (sp->policy != IPSEC_POLICY_DISCARD && 302105197Ssam sp->policy != IPSEC_POLICY_NONE) { 303105197Ssam ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", 304105197Ssam sp->policy, IPSEC_POLICY_NONE)); 305105197Ssam sp->policy = IPSEC_POLICY_NONE; 306105197Ssam } 307135947Ssam key_addref(sp); 308105197Ssam 309105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 310105197Ssam printf("DP key_allocsp_default returns SP:%p (%u)\n", 311105197Ssam sp, sp->refcnt)); 312105197Ssam return sp; 313105197Ssam} 314105197Ssam#define KEY_ALLOCSP_DEFAULT() \ 315105197Ssam key_allocsp_default(__FILE__, __LINE__) 316105197Ssam 317105197Ssam/* 318105197Ssam * For OUTBOUND packet having a socket. Searching SPD for packet, 319105197Ssam * and return a pointer to SP. 320105197Ssam * OUT: NULL: no apropreate SP found, the following value is set to error. 321105197Ssam * 0 : bypass 322105197Ssam * EACCES : discard packet. 323105197Ssam * ENOENT : ipsec_acquire() in progress, maybe. 324105197Ssam * others : error occured. 325105197Ssam * others: a pointer to SP 326105197Ssam * 327105197Ssam * NOTE: IPv6 mapped adddress concern is implemented here. 328105197Ssam */ 329105197Ssamstruct secpolicy * 330105197Ssamipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) 331105197Ssam{ 332105197Ssam struct secpolicy *sp; 333105197Ssam 334120585Ssam IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); 335120585Ssam IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 336120585Ssam ("invalid direction %u", dir)); 337105197Ssam 338105197Ssam sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); 339105197Ssam if (sp == NULL) /*XXX????*/ 340105197Ssam sp = KEY_ALLOCSP_DEFAULT(); 341120585Ssam IPSEC_ASSERT(sp != NULL, ("null SP")); 342105197Ssam return sp; 343105197Ssam} 344105197Ssam 345105197Ssam/* 346105197Ssam * For OUTBOUND packet having a socket. Searching SPD for packet, 347105197Ssam * and return a pointer to SP. 348105197Ssam * OUT: NULL: no apropreate SP found, the following value is set to error. 349105197Ssam * 0 : bypass 350105197Ssam * EACCES : discard packet. 351105197Ssam * ENOENT : ipsec_acquire() in progress, maybe. 352105197Ssam * others : error occured. 353105197Ssam * others: a pointer to SP 354105197Ssam * 355105197Ssam * NOTE: IPv6 mapped adddress concern is implemented here. 356105197Ssam */ 357186508Sbzstatic struct secpolicy * 358186508Sbzipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp, int *error) 359105197Ssam{ 360183550Szec INIT_VNET_IPSEC(curvnet); 361105197Ssam struct inpcbpolicy *pcbsp = NULL; 362105197Ssam struct secpolicy *currsp = NULL; /* policy on socket */ 363105197Ssam struct secpolicy *sp; 364105197Ssam 365120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 366120585Ssam IPSEC_ASSERT(inp != NULL, ("null inpcb")); 367120585Ssam IPSEC_ASSERT(error != NULL, ("null error")); 368120585Ssam IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 369120585Ssam ("invalid direction %u", dir)); 370105197Ssam 371111396Sjlemon /* set spidx in pcb */ 372111396Sjlemon if (inp->inp_vflag & INP_IPV6PROTO) { 373111682Ssam#ifdef INET6 374186527Sbz *error = ipsec6_setspidx_inpcb(m, inp); 375186141Sbz pcbsp = inp->inp_sp; 376111682Ssam#else 377111682Ssam *error = EINVAL; /* should not happen */ 378111682Ssam#endif 379111396Sjlemon } else { 380105197Ssam *error = ipsec4_setspidx_inpcb(m, inp); 381105197Ssam pcbsp = inp->inp_sp; 382105197Ssam } 383105197Ssam if (*error) 384105197Ssam return NULL; 385105197Ssam 386120585Ssam IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); 387105197Ssam switch (dir) { 388105197Ssam case IPSEC_DIR_INBOUND: 389105197Ssam currsp = pcbsp->sp_in; 390105197Ssam break; 391105197Ssam case IPSEC_DIR_OUTBOUND: 392105197Ssam currsp = pcbsp->sp_out; 393105197Ssam break; 394105197Ssam } 395120585Ssam IPSEC_ASSERT(currsp != NULL, ("null currsp")); 396105197Ssam 397105197Ssam if (pcbsp->priv) { /* when privilieged socket */ 398105197Ssam switch (currsp->policy) { 399105197Ssam case IPSEC_POLICY_BYPASS: 400105197Ssam case IPSEC_POLICY_IPSEC: 401135947Ssam key_addref(currsp); 402105197Ssam sp = currsp; 403105197Ssam break; 404105197Ssam 405105197Ssam case IPSEC_POLICY_ENTRUST: 406105197Ssam /* look for a policy in SPD */ 407105197Ssam sp = KEY_ALLOCSP(&currsp->spidx, dir); 408105197Ssam if (sp == NULL) /* no SP found */ 409105197Ssam sp = KEY_ALLOCSP_DEFAULT(); 410105197Ssam break; 411105197Ssam 412105197Ssam default: 413120585Ssam ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", 414120585Ssam __func__, currsp->policy)); 415105197Ssam *error = EINVAL; 416105197Ssam return NULL; 417105197Ssam } 418105197Ssam } else { /* unpriv, SPD has policy */ 419105197Ssam sp = KEY_ALLOCSP(&currsp->spidx, dir); 420105197Ssam if (sp == NULL) { /* no SP found */ 421105197Ssam switch (currsp->policy) { 422105197Ssam case IPSEC_POLICY_BYPASS: 423120585Ssam ipseclog((LOG_ERR, "%s: Illegal policy for " 424120585Ssam "non-priviliged defined %d\n", 425120585Ssam __func__, currsp->policy)); 426105197Ssam *error = EINVAL; 427105197Ssam return NULL; 428105197Ssam 429105197Ssam case IPSEC_POLICY_ENTRUST: 430105197Ssam sp = KEY_ALLOCSP_DEFAULT(); 431105197Ssam break; 432105197Ssam 433105197Ssam case IPSEC_POLICY_IPSEC: 434135947Ssam key_addref(currsp); 435105197Ssam sp = currsp; 436105197Ssam break; 437105197Ssam 438105197Ssam default: 439120585Ssam ipseclog((LOG_ERR, "%s: Invalid policy for " 440120585Ssam "PCB %d\n", __func__, currsp->policy)); 441105197Ssam *error = EINVAL; 442105197Ssam return NULL; 443105197Ssam } 444105197Ssam } 445105197Ssam } 446120585Ssam IPSEC_ASSERT(sp != NULL, 447120585Ssam ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); 448105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 449120585Ssam printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", 450120585Ssam __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); 451105197Ssam return sp; 452105197Ssam} 453105197Ssam 454105197Ssam/* 455105197Ssam * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, 456105197Ssam * and return a pointer to SP. 457105197Ssam * OUT: positive: a pointer to the entry for security policy leaf matched. 458105197Ssam * NULL: no apropreate SP found, the following value is set to error. 459105197Ssam * 0 : bypass 460105197Ssam * EACCES : discard packet. 461105197Ssam * ENOENT : ipsec_acquire() in progress, maybe. 462105197Ssam * others : error occured. 463105197Ssam */ 464105197Ssamstruct secpolicy * 465186530Sbzipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error) 466105197Ssam{ 467183550Szec INIT_VNET_IPSEC(curvnet); 468105197Ssam struct secpolicyindex spidx; 469105197Ssam struct secpolicy *sp; 470105197Ssam 471120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 472120585Ssam IPSEC_ASSERT(error != NULL, ("null error")); 473120585Ssam IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 474120585Ssam ("invalid direction %u", dir)); 475105197Ssam 476105197Ssam sp = NULL; 477105197Ssam if (key_havesp(dir)) { 478108533Sschweikh /* Make an index to look for a policy. */ 479105197Ssam *error = ipsec_setspidx(m, &spidx, 480105197Ssam (flag & IP_FORWARDING) ? 0 : 1); 481105197Ssam if (*error != 0) { 482120585Ssam DPRINTF(("%s: setpidx failed, dir %u flag %u\n", 483120585Ssam __func__, dir, flag)); 484105197Ssam return NULL; 485105197Ssam } 486105197Ssam spidx.dir = dir; 487105197Ssam 488105197Ssam sp = KEY_ALLOCSP(&spidx, dir); 489105197Ssam } 490105197Ssam if (sp == NULL) /* no SP found, use system default */ 491105197Ssam sp = KEY_ALLOCSP_DEFAULT(); 492120585Ssam IPSEC_ASSERT(sp != NULL, ("null SP")); 493105197Ssam return sp; 494105197Ssam} 495105197Ssam 496105197Ssamstruct secpolicy * 497186530Sbzipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, 498186530Sbz struct inpcb *inp) 499105197Ssam{ 500183550Szec INIT_VNET_IPSEC(curvnet); 501105197Ssam struct secpolicy *sp; 502105197Ssam 503105197Ssam *error = 0; 504105197Ssam if (inp == NULL) 505105197Ssam sp = ipsec_getpolicybyaddr(m, dir, flag, error); 506105197Ssam else 507105197Ssam sp = ipsec_getpolicybysock(m, dir, inp, error); 508105197Ssam if (sp == NULL) { 509120585Ssam IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); 510181803Sbz V_ipsec4stat.ips_out_inval++; 511105197Ssam return NULL; 512105197Ssam } 513120585Ssam IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); 514105197Ssam switch (sp->policy) { 515105197Ssam case IPSEC_POLICY_ENTRUST: 516105197Ssam default: 517120585Ssam printf("%s: invalid policy %u\n", __func__, sp->policy); 518105197Ssam /* fall thru... */ 519105197Ssam case IPSEC_POLICY_DISCARD: 520181803Sbz V_ipsec4stat.ips_out_polvio++; 521105197Ssam *error = -EINVAL; /* packet is discarded by caller */ 522105197Ssam break; 523105197Ssam case IPSEC_POLICY_BYPASS: 524105197Ssam case IPSEC_POLICY_NONE: 525105197Ssam KEY_FREESP(&sp); 526105197Ssam sp = NULL; /* NB: force NULL result */ 527105197Ssam break; 528105197Ssam case IPSEC_POLICY_IPSEC: 529105197Ssam if (sp->req == NULL) /* acquire an SA */ 530105197Ssam *error = key_spdacquire(sp); 531105197Ssam break; 532105197Ssam } 533105197Ssam if (*error != 0) { 534105197Ssam KEY_FREESP(&sp); 535105197Ssam sp = NULL; 536105197Ssam } 537105197Ssam return sp; 538105197Ssam} 539105197Ssam 540105197Ssamstatic int 541186530Sbzipsec4_setspidx_inpcb(struct mbuf *m, struct inpcb *pcb) 542105197Ssam{ 543105197Ssam int error; 544105197Ssam 545120585Ssam IPSEC_ASSERT(pcb != NULL, ("null pcb")); 546120585Ssam IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); 547120585Ssam IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, 548120585Ssam ("null sp_in || sp_out")); 549105197Ssam 550105197Ssam error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); 551105197Ssam if (error == 0) { 552105197Ssam pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 553105197Ssam pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; 554105197Ssam pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 555105197Ssam } else { 556105197Ssam bzero(&pcb->inp_sp->sp_in->spidx, 557105197Ssam sizeof (pcb->inp_sp->sp_in->spidx)); 558105197Ssam bzero(&pcb->inp_sp->sp_out->spidx, 559105197Ssam sizeof (pcb->inp_sp->sp_in->spidx)); 560105197Ssam } 561105197Ssam return error; 562105197Ssam} 563105197Ssam 564105197Ssam#ifdef INET6 565105197Ssamstatic int 566186530Sbzipsec6_setspidx_inpcb(struct mbuf *m, struct inpcb *pcb) 567105197Ssam{ 568105197Ssam int error; 569105197Ssam 570120585Ssam IPSEC_ASSERT(pcb != NULL, ("null pcb")); 571186141Sbz IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); 572186141Sbz IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, 573120585Ssam ("null sp_in || sp_out")); 574105197Ssam 575186528Sbz error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); 576186528Sbz if (error == 0) { 577186528Sbz pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 578186528Sbz pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; 579186528Sbz pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 580186528Sbz } else { 581186528Sbz bzero(&pcb->inp_sp->sp_in->spidx, 582186528Sbz sizeof(pcb->inp_sp->sp_in->spidx)); 583186528Sbz bzero(&pcb->inp_sp->sp_out->spidx, 584186528Sbz sizeof(pcb->inp_sp->sp_in->spidx)); 585186528Sbz } 586105197Ssam 587105197Ssam return error; 588105197Ssam} 589105197Ssam#endif 590105197Ssam 591105197Ssam/* 592105197Ssam * configure security policy index (src/dst/proto/sport/dport) 593105197Ssam * by looking at the content of mbuf. 594105197Ssam * the caller is responsible for error recovery (like clearing up spidx). 595105197Ssam */ 596105197Ssamstatic int 597186530Sbzipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) 598105197Ssam{ 599183550Szec INIT_VNET_IPSEC(curvnet); 600105197Ssam struct ip *ip = NULL; 601105197Ssam struct ip ipbuf; 602105197Ssam u_int v; 603105197Ssam struct mbuf *n; 604105197Ssam int len; 605105197Ssam int error; 606105197Ssam 607120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 608105197Ssam 609105197Ssam /* 610105197Ssam * validate m->m_pkthdr.len. we see incorrect length if we 611105197Ssam * mistakenly call this function with inconsistent mbuf chain 612105197Ssam * (like 4.4BSD tcp/udp processing). XXX should we panic here? 613105197Ssam */ 614105197Ssam len = 0; 615105197Ssam for (n = m; n; n = n->m_next) 616105197Ssam len += n->m_len; 617105197Ssam if (m->m_pkthdr.len != len) { 618105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 619120585Ssam printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", 620120585Ssam __func__, len, m->m_pkthdr.len)); 621105197Ssam return EINVAL; 622105197Ssam } 623105197Ssam 624105197Ssam if (m->m_pkthdr.len < sizeof(struct ip)) { 625105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 626120585Ssam printf("%s: pkthdr len(%d) too small (v4), ignored.\n", 627120585Ssam __func__, m->m_pkthdr.len)); 628105197Ssam return EINVAL; 629105197Ssam } 630105197Ssam 631105197Ssam if (m->m_len >= sizeof(*ip)) 632105197Ssam ip = mtod(m, struct ip *); 633105197Ssam else { 634105197Ssam m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); 635105197Ssam ip = &ipbuf; 636105197Ssam } 637105197Ssam#ifdef _IP_VHL 638105197Ssam v = _IP_VHL_V(ip->ip_vhl); 639105197Ssam#else 640105197Ssam v = ip->ip_v; 641105197Ssam#endif 642105197Ssam switch (v) { 643105197Ssam case 4: 644105197Ssam error = ipsec4_setspidx_ipaddr(m, spidx); 645105197Ssam if (error) 646105197Ssam return error; 647105197Ssam ipsec4_get_ulp(m, spidx, needport); 648105197Ssam return 0; 649105197Ssam#ifdef INET6 650105197Ssam case 6: 651105197Ssam if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { 652105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 653120585Ssam printf("%s: pkthdr len(%d) too small (v6), " 654120585Ssam "ignored\n", __func__, m->m_pkthdr.len)); 655105197Ssam return EINVAL; 656105197Ssam } 657105197Ssam error = ipsec6_setspidx_ipaddr(m, spidx); 658105197Ssam if (error) 659105197Ssam return error; 660105197Ssam ipsec6_get_ulp(m, spidx, needport); 661105197Ssam return 0; 662105197Ssam#endif 663105197Ssam default: 664105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 665120585Ssam printf("%s: " "unknown IP version %u, ignored.\n", 666120585Ssam __func__, v)); 667105197Ssam return EINVAL; 668105197Ssam } 669105197Ssam} 670105197Ssam 671105197Ssamstatic void 672105197Ssamipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 673105197Ssam{ 674105197Ssam u_int8_t nxt; 675105197Ssam int off; 676105197Ssam 677105197Ssam /* sanity check */ 678120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 679120585Ssam IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); 680105197Ssam 681105197Ssam /* NB: ip_input() flips it into host endian XXX need more checking */ 682105197Ssam if (m->m_len < sizeof (struct ip)) { 683105197Ssam struct ip *ip = mtod(m, struct ip *); 684105197Ssam if (ip->ip_off & (IP_MF | IP_OFFMASK)) 685105197Ssam goto done; 686105197Ssam#ifdef _IP_VHL 687105197Ssam off = _IP_VHL_HL(ip->ip_vhl) << 2; 688105197Ssam#else 689105197Ssam off = ip->ip_hl << 2; 690105197Ssam#endif 691105197Ssam nxt = ip->ip_p; 692105197Ssam } else { 693105197Ssam struct ip ih; 694105197Ssam 695105197Ssam m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 696105197Ssam if (ih.ip_off & (IP_MF | IP_OFFMASK)) 697105197Ssam goto done; 698105197Ssam#ifdef _IP_VHL 699105197Ssam off = _IP_VHL_HL(ih.ip_vhl) << 2; 700105197Ssam#else 701105197Ssam off = ih.ip_hl << 2; 702105197Ssam#endif 703105197Ssam nxt = ih.ip_p; 704105197Ssam } 705105197Ssam 706105197Ssam while (off < m->m_pkthdr.len) { 707105197Ssam struct ip6_ext ip6e; 708105197Ssam struct tcphdr th; 709105197Ssam struct udphdr uh; 710105197Ssam 711105197Ssam switch (nxt) { 712105197Ssam case IPPROTO_TCP: 713105197Ssam spidx->ul_proto = nxt; 714105197Ssam if (!needport) 715105197Ssam goto done_proto; 716105197Ssam if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 717105197Ssam goto done; 718105197Ssam m_copydata(m, off, sizeof (th), (caddr_t) &th); 719105197Ssam spidx->src.sin.sin_port = th.th_sport; 720105197Ssam spidx->dst.sin.sin_port = th.th_dport; 721105197Ssam return; 722105197Ssam case IPPROTO_UDP: 723105197Ssam spidx->ul_proto = nxt; 724105197Ssam if (!needport) 725105197Ssam goto done_proto; 726105197Ssam if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 727105197Ssam goto done; 728105197Ssam m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 729105197Ssam spidx->src.sin.sin_port = uh.uh_sport; 730105197Ssam spidx->dst.sin.sin_port = uh.uh_dport; 731105197Ssam return; 732105197Ssam case IPPROTO_AH: 733143323Ssam if (off + sizeof(ip6e) > m->m_pkthdr.len) 734105197Ssam goto done; 735105197Ssam /* XXX sigh, this works but is totally bogus */ 736105197Ssam m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 737105197Ssam off += (ip6e.ip6e_len + 2) << 2; 738105197Ssam nxt = ip6e.ip6e_nxt; 739105197Ssam break; 740105197Ssam case IPPROTO_ICMP: 741105197Ssam default: 742105197Ssam /* XXX intermediate headers??? */ 743105197Ssam spidx->ul_proto = nxt; 744105197Ssam goto done_proto; 745105197Ssam } 746105197Ssam } 747105197Ssamdone: 748105197Ssam spidx->ul_proto = IPSEC_ULPROTO_ANY; 749105197Ssamdone_proto: 750105197Ssam spidx->src.sin.sin_port = IPSEC_PORT_ANY; 751105197Ssam spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 752105197Ssam} 753105197Ssam 754105197Ssam/* assumes that m is sane */ 755105197Ssamstatic int 756105197Ssamipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 757105197Ssam{ 758105197Ssam static const struct sockaddr_in template = { 759105197Ssam sizeof (struct sockaddr_in), 760105197Ssam AF_INET, 761105197Ssam 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 762105197Ssam }; 763105197Ssam 764105197Ssam spidx->src.sin = template; 765105197Ssam spidx->dst.sin = template; 766105197Ssam 767105197Ssam if (m->m_len < sizeof (struct ip)) { 768105197Ssam m_copydata(m, offsetof(struct ip, ip_src), 769105197Ssam sizeof (struct in_addr), 770105197Ssam (caddr_t) &spidx->src.sin.sin_addr); 771105197Ssam m_copydata(m, offsetof(struct ip, ip_dst), 772105197Ssam sizeof (struct in_addr), 773105197Ssam (caddr_t) &spidx->dst.sin.sin_addr); 774105197Ssam } else { 775105197Ssam struct ip *ip = mtod(m, struct ip *); 776105197Ssam spidx->src.sin.sin_addr = ip->ip_src; 777105197Ssam spidx->dst.sin.sin_addr = ip->ip_dst; 778105197Ssam } 779105197Ssam 780105197Ssam spidx->prefs = sizeof(struct in_addr) << 3; 781105197Ssam spidx->prefd = sizeof(struct in_addr) << 3; 782105197Ssam 783105197Ssam return 0; 784105197Ssam} 785105197Ssam 786105197Ssam#ifdef INET6 787105197Ssamstatic void 788186530Sbzipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 789105197Ssam{ 790183550Szec INIT_VNET_IPSEC(curvnet); 791105197Ssam int off, nxt; 792105197Ssam struct tcphdr th; 793105197Ssam struct udphdr uh; 794170121Sbz struct icmp6_hdr ih; 795105197Ssam 796105197Ssam /* sanity check */ 797105197Ssam if (m == NULL) 798120585Ssam panic("%s: NULL pointer was passed.\n", __func__); 799105197Ssam 800105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 801120585Ssam printf("%s:\n", __func__); kdebug_mbuf(m)); 802105197Ssam 803105197Ssam /* set default */ 804105197Ssam spidx->ul_proto = IPSEC_ULPROTO_ANY; 805105197Ssam ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; 806105197Ssam ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; 807105197Ssam 808105197Ssam nxt = -1; 809105197Ssam off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 810105197Ssam if (off < 0 || m->m_pkthdr.len < off) 811105197Ssam return; 812105197Ssam 813105197Ssam switch (nxt) { 814105197Ssam case IPPROTO_TCP: 815105197Ssam spidx->ul_proto = nxt; 816105197Ssam if (!needport) 817105197Ssam break; 818105197Ssam if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 819105197Ssam break; 820105197Ssam m_copydata(m, off, sizeof(th), (caddr_t)&th); 821105197Ssam ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; 822105197Ssam ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; 823105197Ssam break; 824105197Ssam case IPPROTO_UDP: 825105197Ssam spidx->ul_proto = nxt; 826105197Ssam if (!needport) 827105197Ssam break; 828105197Ssam if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 829105197Ssam break; 830105197Ssam m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 831105197Ssam ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; 832105197Ssam ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; 833105197Ssam break; 834105197Ssam case IPPROTO_ICMPV6: 835170121Sbz spidx->ul_proto = nxt; 836170121Sbz if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 837170121Sbz break; 838170121Sbz m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 839170121Sbz ((struct sockaddr_in6 *)&spidx->src)->sin6_port = 840170121Sbz htons((uint16_t)ih.icmp6_type); 841170121Sbz ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = 842170121Sbz htons((uint16_t)ih.icmp6_code); 843170121Sbz break; 844105197Ssam default: 845105197Ssam /* XXX intermediate headers??? */ 846105197Ssam spidx->ul_proto = nxt; 847105197Ssam break; 848105197Ssam } 849105197Ssam} 850105197Ssam 851105197Ssam/* assumes that m is sane */ 852105197Ssamstatic int 853186530Sbzipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 854105197Ssam{ 855105197Ssam struct ip6_hdr *ip6 = NULL; 856105197Ssam struct ip6_hdr ip6buf; 857105197Ssam struct sockaddr_in6 *sin6; 858105197Ssam 859105197Ssam if (m->m_len >= sizeof(*ip6)) 860105197Ssam ip6 = mtod(m, struct ip6_hdr *); 861105197Ssam else { 862105197Ssam m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 863105197Ssam ip6 = &ip6buf; 864105197Ssam } 865105197Ssam 866105197Ssam sin6 = (struct sockaddr_in6 *)&spidx->src; 867105197Ssam bzero(sin6, sizeof(*sin6)); 868105197Ssam sin6->sin6_family = AF_INET6; 869105197Ssam sin6->sin6_len = sizeof(struct sockaddr_in6); 870105197Ssam bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); 871105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 872105197Ssam sin6->sin6_addr.s6_addr16[1] = 0; 873105197Ssam sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); 874105197Ssam } 875105197Ssam spidx->prefs = sizeof(struct in6_addr) << 3; 876105197Ssam 877105197Ssam sin6 = (struct sockaddr_in6 *)&spidx->dst; 878105197Ssam bzero(sin6, sizeof(*sin6)); 879105197Ssam sin6->sin6_family = AF_INET6; 880105197Ssam sin6->sin6_len = sizeof(struct sockaddr_in6); 881105197Ssam bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); 882105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 883105197Ssam sin6->sin6_addr.s6_addr16[1] = 0; 884105197Ssam sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); 885105197Ssam } 886105197Ssam spidx->prefd = sizeof(struct in6_addr) << 3; 887105197Ssam 888105197Ssam return 0; 889105197Ssam} 890105197Ssam#endif 891105197Ssam 892105197Ssamstatic void 893186530Sbzipsec_delpcbpolicy(struct inpcbpolicy *p) 894105197Ssam{ 895119643Ssam free(p, M_IPSEC_INPCB); 896105197Ssam} 897105197Ssam 898105197Ssam/* initialize policy in PCB */ 899105197Ssamint 900186530Sbzipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) 901105197Ssam{ 902183550Szec INIT_VNET_IPSEC(curvnet); 903105197Ssam struct inpcbpolicy *new; 904105197Ssam 905105197Ssam /* sanity check. */ 906105197Ssam if (so == NULL || pcb_sp == NULL) 907120585Ssam panic("%s: NULL pointer was passed.\n", __func__); 908105197Ssam 909105197Ssam new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), 910119643Ssam M_IPSEC_INPCB, M_NOWAIT|M_ZERO); 911105197Ssam if (new == NULL) { 912120585Ssam ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 913105197Ssam return ENOBUFS; 914105197Ssam } 915105197Ssam 916120585Ssam new->priv = IPSEC_IS_PRIVILEGED_SO(so); 917105197Ssam 918105197Ssam if ((new->sp_in = KEY_NEWSP()) == NULL) { 919105197Ssam ipsec_delpcbpolicy(new); 920105197Ssam return ENOBUFS; 921105197Ssam } 922105197Ssam new->sp_in->state = IPSEC_SPSTATE_ALIVE; 923105197Ssam new->sp_in->policy = IPSEC_POLICY_ENTRUST; 924105197Ssam 925105197Ssam if ((new->sp_out = KEY_NEWSP()) == NULL) { 926105197Ssam KEY_FREESP(&new->sp_in); 927105197Ssam ipsec_delpcbpolicy(new); 928105197Ssam return ENOBUFS; 929105197Ssam } 930105197Ssam new->sp_out->state = IPSEC_SPSTATE_ALIVE; 931105197Ssam new->sp_out->policy = IPSEC_POLICY_ENTRUST; 932105197Ssam 933105197Ssam *pcb_sp = new; 934105197Ssam 935105197Ssam return 0; 936105197Ssam} 937105197Ssam 938105197Ssam/* copy old ipsec policy into new */ 939105197Ssamint 940186530Sbzipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new) 941105197Ssam{ 942105197Ssam struct secpolicy *sp; 943105197Ssam 944105197Ssam sp = ipsec_deepcopy_policy(old->sp_in); 945105197Ssam if (sp) { 946105197Ssam KEY_FREESP(&new->sp_in); 947105197Ssam new->sp_in = sp; 948105197Ssam } else 949105197Ssam return ENOBUFS; 950105197Ssam 951105197Ssam sp = ipsec_deepcopy_policy(old->sp_out); 952105197Ssam if (sp) { 953105197Ssam KEY_FREESP(&new->sp_out); 954105197Ssam new->sp_out = sp; 955105197Ssam } else 956105197Ssam return ENOBUFS; 957105197Ssam 958105197Ssam new->priv = old->priv; 959105197Ssam 960105197Ssam return 0; 961105197Ssam} 962105197Ssam 963119643Ssamstruct ipsecrequest * 964119643Ssamipsec_newisr(void) 965119643Ssam{ 966119643Ssam struct ipsecrequest *p; 967119643Ssam 968119643Ssam p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); 969119643Ssam if (p != NULL) 970120585Ssam IPSECREQUEST_LOCK_INIT(p); 971119643Ssam return p; 972119643Ssam} 973119643Ssam 974119643Ssamvoid 975119643Ssamipsec_delisr(struct ipsecrequest *p) 976119643Ssam{ 977120585Ssam IPSECREQUEST_LOCK_DESTROY(p); 978119643Ssam free(p, M_IPSEC_SR); 979119643Ssam} 980119643Ssam 981105197Ssam/* deep-copy a policy in PCB */ 982105197Ssamstatic struct secpolicy * 983186530Sbzipsec_deepcopy_policy(struct secpolicy *src) 984105197Ssam{ 985105197Ssam struct ipsecrequest *newchain = NULL; 986105197Ssam struct ipsecrequest *p; 987105197Ssam struct ipsecrequest **q; 988105197Ssam struct ipsecrequest *r; 989105197Ssam struct secpolicy *dst; 990105197Ssam 991105197Ssam if (src == NULL) 992105197Ssam return NULL; 993105197Ssam dst = KEY_NEWSP(); 994105197Ssam if (dst == NULL) 995105197Ssam return NULL; 996105197Ssam 997105197Ssam /* 998105197Ssam * deep-copy IPsec request chain. This is required since struct 999105197Ssam * ipsecrequest is not reference counted. 1000105197Ssam */ 1001105197Ssam q = &newchain; 1002105197Ssam for (p = src->req; p; p = p->next) { 1003119643Ssam *q = ipsec_newisr(); 1004105197Ssam if (*q == NULL) 1005105197Ssam goto fail; 1006105197Ssam (*q)->saidx.proto = p->saidx.proto; 1007105197Ssam (*q)->saidx.mode = p->saidx.mode; 1008105197Ssam (*q)->level = p->level; 1009105197Ssam (*q)->saidx.reqid = p->saidx.reqid; 1010105197Ssam 1011105197Ssam bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); 1012105197Ssam bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); 1013105197Ssam 1014105197Ssam (*q)->sp = dst; 1015105197Ssam 1016105197Ssam q = &((*q)->next); 1017105197Ssam } 1018105197Ssam 1019105197Ssam dst->req = newchain; 1020105197Ssam dst->state = src->state; 1021105197Ssam dst->policy = src->policy; 1022105197Ssam /* do not touch the refcnt fields */ 1023105197Ssam 1024105197Ssam return dst; 1025105197Ssam 1026105197Ssamfail: 1027105197Ssam for (p = newchain; p; p = r) { 1028105197Ssam r = p->next; 1029119643Ssam ipsec_delisr(p); 1030105197Ssam p = NULL; 1031105197Ssam } 1032105197Ssam return NULL; 1033105197Ssam} 1034105197Ssam 1035105197Ssam/* set policy and ipsec request if present. */ 1036105197Ssamstatic int 1037186530Sbzipsec_set_policy(struct secpolicy **pcb_sp, int optname, caddr_t request, 1038186530Sbz size_t len, struct ucred *cred) 1039105197Ssam{ 1040183550Szec INIT_VNET_IPSEC(curvnet); 1041105197Ssam struct sadb_x_policy *xpl; 1042105197Ssam struct secpolicy *newsp = NULL; 1043105197Ssam int error; 1044105197Ssam 1045105197Ssam /* sanity check. */ 1046105197Ssam if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) 1047105197Ssam return EINVAL; 1048105197Ssam if (len < sizeof(*xpl)) 1049105197Ssam return EINVAL; 1050105197Ssam xpl = (struct sadb_x_policy *)request; 1051105197Ssam 1052105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1053120585Ssam printf("%s: passed policy\n", __func__); 1054105197Ssam kdebug_sadb_x_policy((struct sadb_ext *)xpl)); 1055105197Ssam 1056105197Ssam /* check policy type */ 1057105197Ssam /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ 1058105197Ssam if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD 1059105197Ssam || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) 1060105197Ssam return EINVAL; 1061105197Ssam 1062105197Ssam /* check privileged socket */ 1063175892Sbz if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { 1064175892Sbz error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); 1065175892Sbz if (error) 1066175892Sbz return EACCES; 1067175892Sbz } 1068105197Ssam 1069105197Ssam /* allocation new SP entry */ 1070105197Ssam if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) 1071105197Ssam return error; 1072105197Ssam 1073105197Ssam newsp->state = IPSEC_SPSTATE_ALIVE; 1074105197Ssam 1075105197Ssam /* clear old SP and set new SP */ 1076105197Ssam KEY_FREESP(pcb_sp); 1077105197Ssam *pcb_sp = newsp; 1078105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1079120585Ssam printf("%s: new policy\n", __func__); 1080105197Ssam kdebug_secpolicy(newsp)); 1081105197Ssam 1082105197Ssam return 0; 1083105197Ssam} 1084105197Ssam 1085105197Ssamstatic int 1086186530Sbzipsec_get_policy(struct secpolicy *pcb_sp, struct mbuf **mp) 1087105197Ssam{ 1088183550Szec INIT_VNET_IPSEC(curvnet); 1089105197Ssam 1090105197Ssam /* sanity check. */ 1091105197Ssam if (pcb_sp == NULL || mp == NULL) 1092105197Ssam return EINVAL; 1093105197Ssam 1094105197Ssam *mp = key_sp2msg(pcb_sp); 1095105197Ssam if (!*mp) { 1096120585Ssam ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 1097105197Ssam return ENOBUFS; 1098105197Ssam } 1099105197Ssam 1100105197Ssam (*mp)->m_type = MT_DATA; 1101105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1102120585Ssam printf("%s:\n", __func__); kdebug_mbuf(*mp)); 1103105197Ssam 1104105197Ssam return 0; 1105105197Ssam} 1106105197Ssam 1107105197Ssamint 1108186530Sbzipsec4_set_policy(struct inpcb *inp, int optname, caddr_t request, 1109186530Sbz size_t len, struct ucred *cred) 1110105197Ssam{ 1111183550Szec INIT_VNET_IPSEC(curvnet); 1112105197Ssam struct sadb_x_policy *xpl; 1113105197Ssam struct secpolicy **pcb_sp; 1114105197Ssam 1115105197Ssam /* sanity check. */ 1116105197Ssam if (inp == NULL || request == NULL) 1117105197Ssam return EINVAL; 1118105197Ssam if (len < sizeof(*xpl)) 1119105197Ssam return EINVAL; 1120105197Ssam xpl = (struct sadb_x_policy *)request; 1121105197Ssam 1122105197Ssam /* select direction */ 1123105197Ssam switch (xpl->sadb_x_policy_dir) { 1124105197Ssam case IPSEC_DIR_INBOUND: 1125105197Ssam pcb_sp = &inp->inp_sp->sp_in; 1126105197Ssam break; 1127105197Ssam case IPSEC_DIR_OUTBOUND: 1128105197Ssam pcb_sp = &inp->inp_sp->sp_out; 1129105197Ssam break; 1130105197Ssam default: 1131120585Ssam ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 1132105197Ssam xpl->sadb_x_policy_dir)); 1133105197Ssam return EINVAL; 1134105197Ssam } 1135105197Ssam 1136175892Sbz return ipsec_set_policy(pcb_sp, optname, request, len, cred); 1137105197Ssam} 1138105197Ssam 1139105197Ssamint 1140186530Sbzipsec4_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1141186530Sbz struct mbuf **mp) 1142105197Ssam{ 1143183550Szec INIT_VNET_IPSEC(curvnet); 1144105197Ssam struct sadb_x_policy *xpl; 1145105197Ssam struct secpolicy *pcb_sp; 1146105197Ssam 1147105197Ssam /* sanity check. */ 1148105197Ssam if (inp == NULL || request == NULL || mp == NULL) 1149105197Ssam return EINVAL; 1150120585Ssam IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 1151105197Ssam if (len < sizeof(*xpl)) 1152105197Ssam return EINVAL; 1153105197Ssam xpl = (struct sadb_x_policy *)request; 1154105197Ssam 1155105197Ssam /* select direction */ 1156105197Ssam switch (xpl->sadb_x_policy_dir) { 1157105197Ssam case IPSEC_DIR_INBOUND: 1158105197Ssam pcb_sp = inp->inp_sp->sp_in; 1159105197Ssam break; 1160105197Ssam case IPSEC_DIR_OUTBOUND: 1161105197Ssam pcb_sp = inp->inp_sp->sp_out; 1162105197Ssam break; 1163105197Ssam default: 1164120585Ssam ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 1165105197Ssam xpl->sadb_x_policy_dir)); 1166105197Ssam return EINVAL; 1167105197Ssam } 1168105197Ssam 1169105197Ssam return ipsec_get_policy(pcb_sp, mp); 1170105197Ssam} 1171105197Ssam 1172105197Ssam/* delete policy in PCB */ 1173105197Ssamint 1174186530Sbzipsec_delete_pcbpolicy(struct inpcb *inp) 1175105197Ssam{ 1176120585Ssam IPSEC_ASSERT(inp != NULL, ("null inp")); 1177105197Ssam 1178105197Ssam if (inp->inp_sp == NULL) 1179105197Ssam return 0; 1180105197Ssam 1181105197Ssam if (inp->inp_sp->sp_in != NULL) 1182105197Ssam KEY_FREESP(&inp->inp_sp->sp_in); 1183105197Ssam 1184105197Ssam if (inp->inp_sp->sp_out != NULL) 1185105197Ssam KEY_FREESP(&inp->inp_sp->sp_out); 1186105197Ssam 1187105197Ssam ipsec_delpcbpolicy(inp->inp_sp); 1188105197Ssam inp->inp_sp = NULL; 1189105197Ssam 1190105197Ssam return 0; 1191105197Ssam} 1192105197Ssam 1193105197Ssam#ifdef INET6 1194105197Ssamint 1195186530Sbzipsec6_set_policy(struct inpcb *inp, int optname, caddr_t request, 1196186530Sbz size_t len, struct ucred *cred) 1197105197Ssam{ 1198183550Szec INIT_VNET_IPSEC(curvnet); 1199105197Ssam struct sadb_x_policy *xpl; 1200105197Ssam struct secpolicy **pcb_sp; 1201105197Ssam 1202105197Ssam /* sanity check. */ 1203186526Sbz if (inp == NULL || request == NULL) 1204105197Ssam return EINVAL; 1205105197Ssam if (len < sizeof(*xpl)) 1206105197Ssam return EINVAL; 1207105197Ssam xpl = (struct sadb_x_policy *)request; 1208105197Ssam 1209105197Ssam /* select direction */ 1210105197Ssam switch (xpl->sadb_x_policy_dir) { 1211105197Ssam case IPSEC_DIR_INBOUND: 1212186526Sbz pcb_sp = &inp->inp_sp->sp_in; 1213105197Ssam break; 1214105197Ssam case IPSEC_DIR_OUTBOUND: 1215186526Sbz pcb_sp = &inp->inp_sp->sp_out; 1216105197Ssam break; 1217105197Ssam default: 1218120585Ssam ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 1219105197Ssam xpl->sadb_x_policy_dir)); 1220105197Ssam return EINVAL; 1221105197Ssam } 1222105197Ssam 1223175892Sbz return ipsec_set_policy(pcb_sp, optname, request, len, cred); 1224105197Ssam} 1225105197Ssam 1226105197Ssamint 1227186530Sbzipsec6_get_policy(struct inpcb *inp, caddr_t request, size_t len, 1228186530Sbz struct mbuf **mp) 1229105197Ssam{ 1230183550Szec INIT_VNET_IPSEC(curvnet); 1231105197Ssam struct sadb_x_policy *xpl; 1232105197Ssam struct secpolicy *pcb_sp; 1233105197Ssam 1234105197Ssam /* sanity check. */ 1235186526Sbz if (inp == NULL || request == NULL || mp == NULL) 1236105197Ssam return EINVAL; 1237186526Sbz IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 1238105197Ssam if (len < sizeof(*xpl)) 1239105197Ssam return EINVAL; 1240105197Ssam xpl = (struct sadb_x_policy *)request; 1241105197Ssam 1242105197Ssam /* select direction */ 1243105197Ssam switch (xpl->sadb_x_policy_dir) { 1244105197Ssam case IPSEC_DIR_INBOUND: 1245186526Sbz pcb_sp = inp->inp_sp->sp_in; 1246105197Ssam break; 1247105197Ssam case IPSEC_DIR_OUTBOUND: 1248186526Sbz pcb_sp = inp->inp_sp->sp_out; 1249105197Ssam break; 1250105197Ssam default: 1251120585Ssam ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 1252105197Ssam xpl->sadb_x_policy_dir)); 1253105197Ssam return EINVAL; 1254105197Ssam } 1255105197Ssam 1256105197Ssam return ipsec_get_policy(pcb_sp, mp); 1257105197Ssam} 1258105197Ssam#endif 1259105197Ssam 1260105197Ssam/* 1261105197Ssam * return current level. 1262105197Ssam * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 1263105197Ssam */ 1264105197Ssamu_int 1265186530Sbzipsec_get_reqlevel(struct ipsecrequest *isr) 1266105197Ssam{ 1267183550Szec INIT_VNET_IPSEC(curvnet); 1268105197Ssam u_int level = 0; 1269105197Ssam u_int esp_trans_deflev, esp_net_deflev; 1270105197Ssam u_int ah_trans_deflev, ah_net_deflev; 1271105197Ssam 1272120585Ssam IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); 1273120585Ssam IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, 1274120585Ssam ("af family mismatch, src %u, dst %u", 1275105197Ssam isr->sp->spidx.src.sa.sa_family, 1276105197Ssam isr->sp->spidx.dst.sa.sa_family)); 1277105197Ssam 1278105197Ssam/* XXX note that we have ipseclog() expanded here - code sync issue */ 1279105197Ssam#define IPSEC_CHECK_DEFAULT(lev) \ 1280105197Ssam (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ 1281105197Ssam && (lev) != IPSEC_LEVEL_UNIQUE) \ 1282181803Sbz ? (V_ipsec_debug \ 1283105197Ssam ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 1284105197Ssam (lev), IPSEC_LEVEL_REQUIRE) \ 1285105197Ssam : 0), \ 1286105197Ssam (lev) = IPSEC_LEVEL_REQUIRE, \ 1287105197Ssam (lev) \ 1288105197Ssam : (lev)) 1289105197Ssam 1290105197Ssam /* set default level */ 1291105197Ssam switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { 1292105197Ssam#ifdef INET 1293105197Ssam case AF_INET: 1294181803Sbz esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 1295181803Sbz esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 1296181803Sbz ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 1297181803Sbz ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 1298105197Ssam break; 1299105197Ssam#endif 1300105197Ssam#ifdef INET6 1301105197Ssam case AF_INET6: 1302181803Sbz esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 1303181803Sbz esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 1304181803Sbz ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 1305181803Sbz ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 1306105197Ssam break; 1307105197Ssam#endif /* INET6 */ 1308105197Ssam default: 1309120585Ssam panic("%s: unknown af %u", 1310120585Ssam __func__, isr->sp->spidx.src.sa.sa_family); 1311105197Ssam } 1312105197Ssam 1313105197Ssam#undef IPSEC_CHECK_DEFAULT 1314105197Ssam 1315105197Ssam /* set level */ 1316105197Ssam switch (isr->level) { 1317105197Ssam case IPSEC_LEVEL_DEFAULT: 1318105197Ssam switch (isr->saidx.proto) { 1319105197Ssam case IPPROTO_ESP: 1320105197Ssam if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 1321105197Ssam level = esp_net_deflev; 1322105197Ssam else 1323105197Ssam level = esp_trans_deflev; 1324105197Ssam break; 1325105197Ssam case IPPROTO_AH: 1326105197Ssam if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 1327105197Ssam level = ah_net_deflev; 1328105197Ssam else 1329105197Ssam level = ah_trans_deflev; 1330125100Ssam break; 1331105197Ssam case IPPROTO_IPCOMP: 1332105197Ssam /* 1333105197Ssam * we don't really care, as IPcomp document says that 1334105197Ssam * we shouldn't compress small packets 1335105197Ssam */ 1336105197Ssam level = IPSEC_LEVEL_USE; 1337105197Ssam break; 1338105197Ssam default: 1339120585Ssam panic("%s: Illegal protocol defined %u\n", __func__, 1340105197Ssam isr->saidx.proto); 1341105197Ssam } 1342105197Ssam break; 1343105197Ssam 1344105197Ssam case IPSEC_LEVEL_USE: 1345105197Ssam case IPSEC_LEVEL_REQUIRE: 1346105197Ssam level = isr->level; 1347105197Ssam break; 1348105197Ssam case IPSEC_LEVEL_UNIQUE: 1349105197Ssam level = IPSEC_LEVEL_REQUIRE; 1350105197Ssam break; 1351105197Ssam 1352105197Ssam default: 1353120585Ssam panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 1354105197Ssam } 1355105197Ssam 1356105197Ssam return level; 1357105197Ssam} 1358105197Ssam 1359105197Ssam/* 1360105197Ssam * Check security policy requirements against the actual 1361105197Ssam * packet contents. Return one if the packet should be 1362105197Ssam * reject as "invalid"; otherwiser return zero to have the 1363105197Ssam * packet treated as "valid". 1364105197Ssam * 1365105197Ssam * OUT: 1366105197Ssam * 0: valid 1367105197Ssam * 1: invalid 1368105197Ssam */ 1369105197Ssamint 1370105197Ssamipsec_in_reject(struct secpolicy *sp, struct mbuf *m) 1371105197Ssam{ 1372183550Szec INIT_VNET_IPSEC(curvnet); 1373105197Ssam struct ipsecrequest *isr; 1374105197Ssam int need_auth; 1375105197Ssam 1376105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DATA, 1377120585Ssam printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 1378105197Ssam 1379105197Ssam /* check policy */ 1380105197Ssam switch (sp->policy) { 1381105197Ssam case IPSEC_POLICY_DISCARD: 1382105197Ssam return 1; 1383105197Ssam case IPSEC_POLICY_BYPASS: 1384105197Ssam case IPSEC_POLICY_NONE: 1385105197Ssam return 0; 1386105197Ssam } 1387105197Ssam 1388120585Ssam IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 1389120585Ssam ("invalid policy %u", sp->policy)); 1390105197Ssam 1391105197Ssam /* XXX should compare policy against ipsec header history */ 1392105197Ssam 1393105197Ssam need_auth = 0; 1394105197Ssam for (isr = sp->req; isr != NULL; isr = isr->next) { 1395105197Ssam if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) 1396105197Ssam continue; 1397105197Ssam switch (isr->saidx.proto) { 1398105197Ssam case IPPROTO_ESP: 1399105197Ssam if ((m->m_flags & M_DECRYPTED) == 0) { 1400105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1401120585Ssam printf("%s: ESP m_flags:%x\n", __func__, 1402105197Ssam m->m_flags)); 1403105197Ssam return 1; 1404105197Ssam } 1405105197Ssam 1406105197Ssam if (!need_auth && 1407105197Ssam isr->sav != NULL && 1408105197Ssam isr->sav->tdb_authalgxform != NULL && 1409105197Ssam (m->m_flags & M_AUTHIPDGM) == 0) { 1410105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1411120585Ssam printf("%s: ESP/AH m_flags:%x\n", __func__, 1412105197Ssam m->m_flags)); 1413105197Ssam return 1; 1414105197Ssam } 1415105197Ssam break; 1416105197Ssam case IPPROTO_AH: 1417105197Ssam need_auth = 1; 1418105197Ssam if ((m->m_flags & M_AUTHIPHDR) == 0) { 1419105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 1420120585Ssam printf("%s: AH m_flags:%x\n", __func__, 1421105197Ssam m->m_flags)); 1422105197Ssam return 1; 1423105197Ssam } 1424105197Ssam break; 1425105197Ssam case IPPROTO_IPCOMP: 1426105197Ssam /* 1427105197Ssam * we don't really care, as IPcomp document 1428105197Ssam * says that we shouldn't compress small 1429105197Ssam * packets, IPComp policy should always be 1430105197Ssam * treated as being in "use" level. 1431105197Ssam */ 1432105197Ssam break; 1433105197Ssam } 1434105197Ssam } 1435105197Ssam return 0; /* valid */ 1436105197Ssam} 1437105197Ssam 1438105197Ssam/* 1439105197Ssam * Check AH/ESP integrity. 1440105197Ssam * This function is called from tcp_input(), udp_input(), 1441105197Ssam * and {ah,esp}4_input for tunnel mode 1442105197Ssam */ 1443105197Ssamint 1444186530Sbzipsec4_in_reject(struct mbuf *m, struct inpcb *inp) 1445105197Ssam{ 1446183550Szec INIT_VNET_IPSEC(curvnet); 1447105197Ssam struct secpolicy *sp; 1448105197Ssam int error; 1449105197Ssam int result; 1450105197Ssam 1451120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 1452105197Ssam 1453105197Ssam /* get SP for this packet. 1454105197Ssam * When we are called from ip_forward(), we call 1455105197Ssam * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 1456105197Ssam */ 1457105197Ssam if (inp == NULL) 1458105197Ssam sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 1459105197Ssam else 1460105197Ssam sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 1461105197Ssam 1462105197Ssam if (sp != NULL) { 1463105197Ssam result = ipsec_in_reject(sp, m); 1464105197Ssam if (result) 1465181803Sbz V_ipsec4stat.ips_in_polvio++; 1466105197Ssam KEY_FREESP(&sp); 1467105197Ssam } else { 1468105197Ssam result = 0; /* XXX should be panic ? 1469105197Ssam * -> No, there may be error. */ 1470105197Ssam } 1471105197Ssam return result; 1472105197Ssam} 1473105197Ssam 1474105197Ssam#ifdef INET6 1475105197Ssam/* 1476105197Ssam * Check AH/ESP integrity. 1477105197Ssam * This function is called from tcp6_input(), udp6_input(), 1478105197Ssam * and {ah,esp}6_input for tunnel mode 1479105197Ssam */ 1480105197Ssamint 1481186530Sbzipsec6_in_reject(struct mbuf *m, struct inpcb *inp) 1482105197Ssam{ 1483183550Szec INIT_VNET_IPSEC(curvnet); 1484105197Ssam struct secpolicy *sp = NULL; 1485105197Ssam int error; 1486105197Ssam int result; 1487105197Ssam 1488105197Ssam /* sanity check */ 1489105197Ssam if (m == NULL) 1490105197Ssam return 0; /* XXX should be panic ? */ 1491105197Ssam 1492105197Ssam /* get SP for this packet. 1493105197Ssam * When we are called from ip_forward(), we call 1494105197Ssam * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 1495105197Ssam */ 1496105197Ssam if (inp == NULL) 1497105197Ssam sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 1498105197Ssam else 1499105197Ssam sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 1500105197Ssam 1501105197Ssam if (sp != NULL) { 1502105197Ssam result = ipsec_in_reject(sp, m); 1503105197Ssam if (result) 1504181803Sbz V_ipsec6stat.ips_in_polvio++; 1505105197Ssam KEY_FREESP(&sp); 1506105197Ssam } else { 1507105197Ssam result = 0; 1508105197Ssam } 1509105197Ssam return result; 1510105197Ssam} 1511105197Ssam#endif 1512105197Ssam 1513105197Ssam/* 1514105197Ssam * compute the byte size to be occupied by IPsec header. 1515105197Ssam * in case it is tunneled, it includes the size of outer IP header. 1516105197Ssam * NOTE: SP passed is free in this function. 1517105197Ssam */ 1518105197Ssamstatic size_t 1519105197Ssamipsec_hdrsiz(struct secpolicy *sp) 1520105197Ssam{ 1521183550Szec INIT_VNET_IPSEC(curvnet); 1522105197Ssam struct ipsecrequest *isr; 1523105197Ssam size_t siz; 1524105197Ssam 1525105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DATA, 1526120585Ssam printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 1527105197Ssam 1528105197Ssam switch (sp->policy) { 1529105197Ssam case IPSEC_POLICY_DISCARD: 1530105197Ssam case IPSEC_POLICY_BYPASS: 1531105197Ssam case IPSEC_POLICY_NONE: 1532105197Ssam return 0; 1533105197Ssam } 1534105197Ssam 1535120585Ssam IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 1536120585Ssam ("invalid policy %u", sp->policy)); 1537105197Ssam 1538105197Ssam siz = 0; 1539105197Ssam for (isr = sp->req; isr != NULL; isr = isr->next) { 1540105197Ssam size_t clen = 0; 1541105197Ssam 1542105197Ssam switch (isr->saidx.proto) { 1543105197Ssam case IPPROTO_ESP: 1544105197Ssam clen = esp_hdrsiz(isr->sav); 1545105197Ssam break; 1546105197Ssam case IPPROTO_AH: 1547105197Ssam clen = ah_hdrsiz(isr->sav); 1548105197Ssam break; 1549105197Ssam case IPPROTO_IPCOMP: 1550105197Ssam clen = sizeof(struct ipcomp); 1551105197Ssam break; 1552105197Ssam } 1553105197Ssam 1554105197Ssam if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 1555105197Ssam switch (isr->saidx.dst.sa.sa_family) { 1556105197Ssam case AF_INET: 1557105197Ssam clen += sizeof(struct ip); 1558105197Ssam break; 1559105197Ssam#ifdef INET6 1560105197Ssam case AF_INET6: 1561105197Ssam clen += sizeof(struct ip6_hdr); 1562105197Ssam break; 1563105197Ssam#endif 1564105197Ssam default: 1565120585Ssam ipseclog((LOG_ERR, "%s: unknown AF %d in " 1566120585Ssam "IPsec tunnel SA\n", __func__, 1567105197Ssam ((struct sockaddr *)&isr->saidx.dst)->sa_family)); 1568105197Ssam break; 1569105197Ssam } 1570105197Ssam } 1571105197Ssam siz += clen; 1572105197Ssam } 1573105197Ssam 1574105197Ssam return siz; 1575105197Ssam} 1576105197Ssam 1577105197Ssam/* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ 1578105197Ssamsize_t 1579186530Sbzipsec4_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) 1580105197Ssam{ 1581183550Szec INIT_VNET_IPSEC(curvnet); 1582105197Ssam struct secpolicy *sp; 1583105197Ssam int error; 1584105197Ssam size_t size; 1585105197Ssam 1586120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 1587105197Ssam 1588105197Ssam /* get SP for this packet. 1589105197Ssam * When we are called from ip_forward(), we call 1590105197Ssam * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 1591105197Ssam */ 1592105197Ssam if (inp == NULL) 1593105197Ssam sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 1594105197Ssam else 1595105197Ssam sp = ipsec_getpolicybysock(m, dir, inp, &error); 1596105197Ssam 1597105197Ssam if (sp != NULL) { 1598105197Ssam size = ipsec_hdrsiz(sp); 1599105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DATA, 1600120585Ssam printf("%s: size:%lu.\n", __func__, 1601105197Ssam (unsigned long)size)); 1602105197Ssam 1603105197Ssam KEY_FREESP(&sp); 1604105197Ssam } else { 1605174038Sbz size = 0; /* XXX should be panic ? 1606174038Sbz * -> No, we are called w/o knowing if 1607174038Sbz * IPsec processing is needed. */ 1608105197Ssam } 1609105197Ssam return size; 1610105197Ssam} 1611105197Ssam 1612105197Ssam#ifdef INET6 1613105197Ssam/* This function is called from ipsec6_hdrsize_tcp(), 1614105197Ssam * and maybe from ip6_forward.() 1615105197Ssam */ 1616105197Ssamsize_t 1617186530Sbzipsec6_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) 1618105197Ssam{ 1619183550Szec INIT_VNET_IPSEC(curvnet); 1620105197Ssam struct secpolicy *sp; 1621105197Ssam int error; 1622105197Ssam size_t size; 1623105197Ssam 1624120585Ssam IPSEC_ASSERT(m != NULL, ("null mbuf")); 1625186526Sbz IPSEC_ASSERT(inp == NULL || inp->inp_socket != NULL, 1626120585Ssam ("socket w/o inpcb")); 1627105197Ssam 1628105197Ssam /* get SP for this packet */ 1629105197Ssam /* XXX Is it right to call with IP_FORWARDING. */ 1630186526Sbz if (inp == NULL) 1631105197Ssam sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 1632105197Ssam else 1633186526Sbz sp = ipsec_getpolicybysock(m, dir, inp, &error); 1634105197Ssam 1635105197Ssam if (sp == NULL) 1636105197Ssam return 0; 1637105197Ssam size = ipsec_hdrsiz(sp); 1638105197Ssam KEYDEBUG(KEYDEBUG_IPSEC_DATA, 1639120585Ssam printf("%s: size:%lu.\n", __func__, (unsigned long)size)); 1640105197Ssam KEY_FREESP(&sp); 1641105197Ssam 1642105197Ssam return size; 1643105197Ssam} 1644105197Ssam#endif /*INET6*/ 1645105197Ssam 1646105197Ssam/* 1647105197Ssam * Check the variable replay window. 1648105197Ssam * ipsec_chkreplay() performs replay check before ICV verification. 1649105197Ssam * ipsec_updatereplay() updates replay bitmap. This must be called after 1650105197Ssam * ICV verification (it also performs replay check, which is usually done 1651105197Ssam * beforehand). 1652105197Ssam * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 1653105197Ssam * 1654105197Ssam * based on RFC 2401. 1655105197Ssam */ 1656105197Ssamint 1657186530Sbzipsec_chkreplay(u_int32_t seq, struct secasvar *sav) 1658105197Ssam{ 1659105197Ssam const struct secreplay *replay; 1660105197Ssam u_int32_t diff; 1661105197Ssam int fr; 1662105197Ssam u_int32_t wsizeb; /* constant: bits of window size */ 1663105197Ssam int frlast; /* constant: last frame */ 1664105197Ssam 1665120585Ssam IPSEC_ASSERT(sav != NULL, ("Null SA")); 1666120585Ssam IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 1667105197Ssam 1668105197Ssam replay = sav->replay; 1669105197Ssam 1670105197Ssam if (replay->wsize == 0) 1671105197Ssam return 1; /* no need to check replay. */ 1672105197Ssam 1673105197Ssam /* constant */ 1674105197Ssam frlast = replay->wsize - 1; 1675105197Ssam wsizeb = replay->wsize << 3; 1676105197Ssam 1677105197Ssam /* sequence number of 0 is invalid */ 1678105197Ssam if (seq == 0) 1679105197Ssam return 0; 1680105197Ssam 1681105197Ssam /* first time is always okay */ 1682105197Ssam if (replay->count == 0) 1683105197Ssam return 1; 1684105197Ssam 1685105197Ssam if (seq > replay->lastseq) { 1686105197Ssam /* larger sequences are okay */ 1687105197Ssam return 1; 1688105197Ssam } else { 1689105197Ssam /* seq is equal or less than lastseq. */ 1690105197Ssam diff = replay->lastseq - seq; 1691105197Ssam 1692105197Ssam /* over range to check, i.e. too old or wrapped */ 1693105197Ssam if (diff >= wsizeb) 1694105197Ssam return 0; 1695105197Ssam 1696105197Ssam fr = frlast - diff / 8; 1697105197Ssam 1698105197Ssam /* this packet already seen ? */ 1699105197Ssam if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1700105197Ssam return 0; 1701105197Ssam 1702105197Ssam /* out of order but good */ 1703105197Ssam return 1; 1704105197Ssam } 1705105197Ssam} 1706105197Ssam 1707105197Ssam/* 1708105197Ssam * check replay counter whether to update or not. 1709105197Ssam * OUT: 0: OK 1710105197Ssam * 1: NG 1711105197Ssam */ 1712105197Ssamint 1713186530Sbzipsec_updatereplay(u_int32_t seq, struct secasvar *sav) 1714105197Ssam{ 1715183550Szec INIT_VNET_IPSEC(curvnet); 1716105197Ssam struct secreplay *replay; 1717105197Ssam u_int32_t diff; 1718105197Ssam int fr; 1719105197Ssam u_int32_t wsizeb; /* constant: bits of window size */ 1720105197Ssam int frlast; /* constant: last frame */ 1721105197Ssam 1722120585Ssam IPSEC_ASSERT(sav != NULL, ("Null SA")); 1723120585Ssam IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 1724105197Ssam 1725105197Ssam replay = sav->replay; 1726105197Ssam 1727105197Ssam if (replay->wsize == 0) 1728105197Ssam goto ok; /* no need to check replay. */ 1729105197Ssam 1730105197Ssam /* constant */ 1731105197Ssam frlast = replay->wsize - 1; 1732105197Ssam wsizeb = replay->wsize << 3; 1733105197Ssam 1734105197Ssam /* sequence number of 0 is invalid */ 1735105197Ssam if (seq == 0) 1736105197Ssam return 1; 1737105197Ssam 1738105197Ssam /* first time */ 1739105197Ssam if (replay->count == 0) { 1740105197Ssam replay->lastseq = seq; 1741105197Ssam bzero(replay->bitmap, replay->wsize); 1742105197Ssam (replay->bitmap)[frlast] = 1; 1743105197Ssam goto ok; 1744105197Ssam } 1745105197Ssam 1746105197Ssam if (seq > replay->lastseq) { 1747105197Ssam /* seq is larger than lastseq. */ 1748105197Ssam diff = seq - replay->lastseq; 1749105197Ssam 1750105197Ssam /* new larger sequence number */ 1751105197Ssam if (diff < wsizeb) { 1752105197Ssam /* In window */ 1753105197Ssam /* set bit for this packet */ 1754105197Ssam vshiftl(replay->bitmap, diff, replay->wsize); 1755105197Ssam (replay->bitmap)[frlast] |= 1; 1756105197Ssam } else { 1757105197Ssam /* this packet has a "way larger" */ 1758105197Ssam bzero(replay->bitmap, replay->wsize); 1759105197Ssam (replay->bitmap)[frlast] = 1; 1760105197Ssam } 1761105197Ssam replay->lastseq = seq; 1762105197Ssam 1763105197Ssam /* larger is good */ 1764105197Ssam } else { 1765105197Ssam /* seq is equal or less than lastseq. */ 1766105197Ssam diff = replay->lastseq - seq; 1767105197Ssam 1768105197Ssam /* over range to check, i.e. too old or wrapped */ 1769105197Ssam if (diff >= wsizeb) 1770105197Ssam return 1; 1771105197Ssam 1772105197Ssam fr = frlast - diff / 8; 1773105197Ssam 1774105197Ssam /* this packet already seen ? */ 1775105197Ssam if ((replay->bitmap)[fr] & (1 << (diff % 8))) 1776105197Ssam return 1; 1777105197Ssam 1778105197Ssam /* mark as seen */ 1779105197Ssam (replay->bitmap)[fr] |= (1 << (diff % 8)); 1780105197Ssam 1781105197Ssam /* out of order but good */ 1782105197Ssam } 1783105197Ssam 1784105197Ssamok: 1785105197Ssam if (replay->count == ~0) { 1786105197Ssam 1787105197Ssam /* set overflow flag */ 1788105197Ssam replay->overflow++; 1789105197Ssam 1790105197Ssam /* don't increment, no more packets accepted */ 1791105197Ssam if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) 1792105197Ssam return 1; 1793105197Ssam 1794120585Ssam ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 1795120585Ssam __func__, replay->overflow, ipsec_logsastr(sav))); 1796105197Ssam } 1797105197Ssam 1798105197Ssam replay->count++; 1799105197Ssam 1800105197Ssam return 0; 1801105197Ssam} 1802105197Ssam 1803105197Ssam/* 1804146893Shmp * shift variable length buffer to left. 1805105197Ssam * IN: bitmap: pointer to the buffer 1806105197Ssam * nbit: the number of to shift. 1807105197Ssam * wsize: buffer size (bytes). 1808105197Ssam */ 1809105197Ssamstatic void 1810186530Sbzvshiftl(unsigned char *bitmap, int nbit, int wsize) 1811105197Ssam{ 1812105197Ssam int s, j, i; 1813105197Ssam unsigned char over; 1814105197Ssam 1815105197Ssam for (j = 0; j < nbit; j += 8) { 1816105197Ssam s = (nbit - j < 8) ? (nbit - j): 8; 1817105197Ssam bitmap[0] <<= s; 1818105197Ssam for (i = 1; i < wsize; i++) { 1819105197Ssam over = (bitmap[i] >> (8 - s)); 1820105197Ssam bitmap[i] <<= s; 1821105197Ssam bitmap[i-1] |= over; 1822105197Ssam } 1823105197Ssam } 1824105197Ssam 1825105197Ssam return; 1826105197Ssam} 1827105197Ssam 1828105197Ssam/* Return a printable string for the IPv4 address. */ 1829105197Ssamstatic char * 1830105197Ssaminet_ntoa4(struct in_addr ina) 1831105197Ssam{ 1832105197Ssam static char buf[4][4 * sizeof "123" + 4]; 1833105197Ssam unsigned char *ucp = (unsigned char *) &ina; 1834105197Ssam static int i = 3; 1835105197Ssam 1836165118Sbz /* XXX-BZ returns static buffer. */ 1837105197Ssam i = (i + 1) % 4; 1838105197Ssam sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, 1839105197Ssam ucp[2] & 0xff, ucp[3] & 0xff); 1840105197Ssam return (buf[i]); 1841105197Ssam} 1842105197Ssam 1843105197Ssam/* Return a printable string for the address. */ 1844105197Ssamchar * 1845105197Ssamipsec_address(union sockaddr_union* sa) 1846105197Ssam{ 1847165222Sbz#ifdef INET6 1848165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 1849165118Sbz#endif 1850105197Ssam switch (sa->sa.sa_family) { 1851159237Spjd#ifdef INET 1852105197Ssam case AF_INET: 1853105197Ssam return inet_ntoa4(sa->sin.sin_addr); 1854105197Ssam#endif /* INET */ 1855105197Ssam 1856159237Spjd#ifdef INET6 1857105197Ssam case AF_INET6: 1858165118Sbz return ip6_sprintf(ip6buf, &sa->sin6.sin6_addr); 1859105197Ssam#endif /* INET6 */ 1860105197Ssam 1861105197Ssam default: 1862105197Ssam return "(unknown address family)"; 1863105197Ssam } 1864105197Ssam} 1865105197Ssam 1866105197Ssamconst char * 1867186530Sbzipsec_logsastr(struct secasvar *sav) 1868105197Ssam{ 1869105197Ssam static char buf[256]; 1870105197Ssam char *p; 1871105197Ssam struct secasindex *saidx = &sav->sah->saidx; 1872105197Ssam 1873120585Ssam IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, 1874120585Ssam ("address family mismatch")); 1875105197Ssam 1876105197Ssam p = buf; 1877105197Ssam snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); 1878105197Ssam while (p && *p) 1879105197Ssam p++; 1880105197Ssam /* NB: only use ipsec_address on one address at a time */ 1881105197Ssam snprintf(p, sizeof (buf) - (p - buf), "src=%s ", 1882105197Ssam ipsec_address(&saidx->src)); 1883105197Ssam while (p && *p) 1884105197Ssam p++; 1885105197Ssam snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", 1886105197Ssam ipsec_address(&saidx->dst)); 1887105197Ssam 1888105197Ssam return buf; 1889105197Ssam} 1890105197Ssam 1891105197Ssamvoid 1892186530Sbzipsec_dumpmbuf(struct mbuf *m) 1893105197Ssam{ 1894105197Ssam int totlen; 1895105197Ssam int i; 1896105197Ssam u_char *p; 1897105197Ssam 1898105197Ssam totlen = 0; 1899105197Ssam printf("---\n"); 1900105197Ssam while (m) { 1901105197Ssam p = mtod(m, u_char *); 1902105197Ssam for (i = 0; i < m->m_len; i++) { 1903105197Ssam printf("%02x ", p[i]); 1904105197Ssam totlen++; 1905105197Ssam if (totlen % 16 == 0) 1906105197Ssam printf("\n"); 1907105197Ssam } 1908105197Ssam m = m->m_next; 1909105197Ssam } 1910105197Ssam if (totlen % 16 != 0) 1911105197Ssam printf("\n"); 1912105197Ssam printf("---\n"); 1913105197Ssam} 1914105197Ssam 1915125100Ssamstatic void 1916125100Ssamipsec_attach(void) 1917125100Ssam{ 1918181803Sbz SECPOLICY_LOCK_INIT(&V_ip4_def_policy); 1919185348Szec V_ip4_def_policy.refcnt = 1; /* NB: disallow free */ 1920125100Ssam} 1921177253SrwatsonSYSINIT(ipsec, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, ipsec_attach, NULL); 1922125100Ssam 1923125100Ssam 1924105197Ssam/* XXX this stuff doesn't belong here... */ 1925105197Ssam 1926105197Ssamstatic struct xformsw* xforms = NULL; 1927105197Ssam 1928105197Ssam/* 1929105197Ssam * Register a transform; typically at system startup. 1930105197Ssam */ 1931105197Ssamvoid 1932105197Ssamxform_register(struct xformsw* xsp) 1933105197Ssam{ 1934105197Ssam xsp->xf_next = xforms; 1935105197Ssam xforms = xsp; 1936105197Ssam} 1937105197Ssam 1938105197Ssam/* 1939105197Ssam * Initialize transform support in an sav. 1940105197Ssam */ 1941105197Ssamint 1942105197Ssamxform_init(struct secasvar *sav, int xftype) 1943105197Ssam{ 1944105197Ssam struct xformsw *xsp; 1945105197Ssam 1946117051Ssam if (sav->tdb_xform != NULL) /* previously initialized */ 1947117051Ssam return 0; 1948105197Ssam for (xsp = xforms; xsp; xsp = xsp->xf_next) 1949105197Ssam if (xsp->xf_type == xftype) 1950105197Ssam return (*xsp->xf_init)(sav, xsp); 1951105197Ssam return EINVAL; 1952105197Ssam} 1953