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 10088768458SSam Leffler #ifdef IPSEC_DEBUG 10188768458SSam Leffler int ipsec_debug = 1; 10288768458SSam Leffler #else 10388768458SSam Leffler int ipsec_debug = 0; 10488768458SSam Leffler #endif 10588768458SSam Leffler 10688768458SSam Leffler /* NB: name changed so netstat doesn't use it */ 1072cb64cb2SGeorge V. Neville-Neil struct ipsecstat ipsec4stat; 10888768458SSam Leffler int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ 10988768458SSam Leffler int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ 11088768458SSam Leffler int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; 11188768458SSam Leffler int ip4_esp_net_deflev = IPSEC_LEVEL_USE; 11288768458SSam Leffler int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; 11388768458SSam Leffler int ip4_ah_net_deflev = IPSEC_LEVEL_USE; 11488768458SSam Leffler struct secpolicy ip4_def_policy; 11588768458SSam Leffler int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 11688768458SSam Leffler int ip4_esp_randpad = -1; 11788768458SSam Leffler /* 11888768458SSam Leffler * Crypto support requirements: 11988768458SSam Leffler * 12088768458SSam Leffler * 1 require hardware support 12188768458SSam Leffler * -1 require software support 12288768458SSam Leffler * 0 take anything 12388768458SSam Leffler */ 1246810ad6fSSam Leffler int crypto_support = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 12588768458SSam Leffler 12688768458SSam Leffler SYSCTL_DECL(_net_inet_ipsec); 12788768458SSam Leffler 12888768458SSam Leffler /* net.inet.ipsec */ 12988768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, 130be6b1304STom Rhodes def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, 131be6b1304STom Rhodes "IPsec default policy."); 13288768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1333377c961STom Rhodes CTLFLAG_RW, &ip4_esp_trans_deflev, 0, "Default ESP transport mode level"); 13488768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1353377c961STom Rhodes CTLFLAG_RW, &ip4_esp_net_deflev, 0, "Default ESP tunnel mode level."); 13688768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1373377c961STom Rhodes CTLFLAG_RW, &ip4_ah_trans_deflev, 0, "AH transfer mode default level."); 13888768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 1393377c961STom Rhodes CTLFLAG_RW, &ip4_ah_net_deflev, 0, "AH tunnel mode default level."); 14088768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, 1413377c961STom Rhodes ah_cleartos, CTLFLAG_RW, &ah_cleartos, 0, 1423377c961STom Rhodes "If set clear type-of-service field when doing AH computation."); 14388768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, 1443377c961STom Rhodes ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, 1453377c961STom Rhodes "If not set clear offset field mask when doing AH computation."); 14688768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, 1473377c961STom Rhodes dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, "Do not fragment bit on encap."); 14888768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, 149be6b1304STom Rhodes ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, 150be6b1304STom Rhodes "Explicit Congestion Notification handling."); 15188768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, 152be6b1304STom Rhodes debug, CTLFLAG_RW, &ipsec_debug, 0, 153be6b1304STom Rhodes "Enable IPsec debugging output when set."); 15488768458SSam Leffler SYSCTL_INT(_net_inet_ipsec, OID_AUTO, 155be6b1304STom Rhodes crypto_support, CTLFLAG_RW, &crypto_support, 0, 156be6b1304STom Rhodes "Crypto driver selection."); 15788768458SSam Leffler SYSCTL_STRUCT(_net_inet_ipsec, OID_AUTO, 1583377c961STom Rhodes ipsecstats, CTLFLAG_RD, &ipsec4stat, ipsecstat, "IPsec IPv4 statistics."); 15988768458SSam Leffler 1606131838bSPawel Jakub Dawidek #ifdef REGRESSION 161dfa9422bSPawel Jakub Dawidek /* 162dfa9422bSPawel Jakub Dawidek * When set to 1, IPsec will send packets with the same sequence number. 163dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side has proper replay attacks detection. 164dfa9422bSPawel Jakub Dawidek */ 165dfa9422bSPawel Jakub Dawidek int ipsec_replay = 0; 166dfa9422bSPawel Jakub Dawidek SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_replay, CTLFLAG_RW, &ipsec_replay, 0, 167dfa9422bSPawel Jakub Dawidek "Emulate replay attack"); 168dfa9422bSPawel Jakub Dawidek /* 169dfa9422bSPawel Jakub Dawidek * When set 1, IPsec will send packets with corrupted HMAC. 170dfa9422bSPawel Jakub Dawidek * This allows to verify if the other side properly detects modified packets. 171dfa9422bSPawel Jakub Dawidek */ 172dfa9422bSPawel Jakub Dawidek int ipsec_integrity = 0; 173dfa9422bSPawel Jakub Dawidek SYSCTL_INT(_net_inet_ipsec, OID_AUTO, test_integrity, CTLFLAG_RW, 174dfa9422bSPawel Jakub Dawidek &ipsec_integrity, 0, "Emulate man-in-the-middle attack"); 1756131838bSPawel Jakub Dawidek #endif 176dfa9422bSPawel Jakub Dawidek 17788768458SSam Leffler #ifdef INET6 1782cb64cb2SGeorge V. Neville-Neil struct ipsecstat ipsec6stat; 17988768458SSam Leffler int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; 18088768458SSam Leffler int ip6_esp_net_deflev = IPSEC_LEVEL_USE; 18188768458SSam Leffler int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; 18288768458SSam Leffler int ip6_ah_net_deflev = IPSEC_LEVEL_USE; 18388768458SSam Leffler int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ 18488768458SSam Leffler 18588768458SSam Leffler SYSCTL_DECL(_net_inet6_ipsec6); 18688768458SSam Leffler 18788768458SSam Leffler /* net.inet6.ipsec6 */ 18888768458SSam Leffler #ifdef COMPAT_KAME 18988768458SSam Leffler SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, 1903377c961STom Rhodes 0, 0, compat_ipsecstats_sysctl, "S", "IPsec IPv6 statistics."); 19188768458SSam Leffler #endif /* COMPAT_KAME */ 19288768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, 1933377c961STom Rhodes def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, "IPsec default policy."); 19488768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, 1953377c961STom Rhodes CTLFLAG_RW, &ip6_esp_trans_deflev, 0, "Default ESP transport mode level."); 19688768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, 1973377c961STom Rhodes CTLFLAG_RW, &ip6_esp_net_deflev, 0, "Default ESP tunnel mode level."); 19888768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, 1993377c961STom Rhodes CTLFLAG_RW, &ip6_ah_trans_deflev, 0, "AH transfer mode default level."); 20088768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, 2013377c961STom Rhodes CTLFLAG_RW, &ip6_ah_net_deflev, 0, "AH tunnel mode default level."); 20288768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, 2033377c961STom Rhodes ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, 2043377c961STom Rhodes "Explicit Congestion Notification handling."); 20588768458SSam Leffler SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, 206be6b1304STom Rhodes debug, CTLFLAG_RW, &ipsec_debug, 0, 207be6b1304STom Rhodes "Enable IPsec debugging output when set."); 2082cb64cb2SGeorge V. Neville-Neil SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, 2093377c961STom Rhodes ipsecstats, CTLFLAG_RD, &ipsec6stat, ipsecstat, "IPsec IPv6 statistics."); 21088768458SSam Leffler #endif /* INET6 */ 21188768458SSam Leffler 21288768458SSam Leffler static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); 21388768458SSam Leffler #ifdef INET6 21488768458SSam Leffler static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); 21588768458SSam Leffler #endif 21688768458SSam Leffler static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); 21788768458SSam Leffler static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 21888768458SSam Leffler static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 21988768458SSam Leffler #ifdef INET6 22088768458SSam Leffler static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); 22188768458SSam Leffler static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); 22288768458SSam Leffler #endif 22388768458SSam Leffler static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); 22488768458SSam Leffler static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); 22588768458SSam Leffler static int ipsec_set_policy __P((struct secpolicy **pcb_sp, 226c26fe973SBjoern A. Zeeb int optname, caddr_t request, size_t len, struct ucred *cred)); 22788768458SSam Leffler static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp)); 22888768458SSam Leffler static void vshiftl __P((unsigned char *, int, int)); 22988768458SSam Leffler static size_t ipsec_hdrsiz __P((struct secpolicy *)); 23088768458SSam Leffler 2316464079fSSam Leffler MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); 2326464079fSSam Leffler 23388768458SSam Leffler /* 23488768458SSam Leffler * Return a held reference to the default SP. 23588768458SSam Leffler */ 23688768458SSam Leffler static struct secpolicy * 23788768458SSam Leffler key_allocsp_default(const char* where, int tag) 23888768458SSam Leffler { 23988768458SSam Leffler struct secpolicy *sp; 24088768458SSam Leffler 24188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 24288768458SSam Leffler printf("DP key_allocsp_default from %s:%u\n", where, tag)); 24388768458SSam Leffler 244603724d3SBjoern A. Zeeb sp = &V_ip4_def_policy; 24588768458SSam Leffler if (sp->policy != IPSEC_POLICY_DISCARD && 24688768458SSam Leffler sp->policy != IPSEC_POLICY_NONE) { 24788768458SSam Leffler ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", 24888768458SSam Leffler sp->policy, IPSEC_POLICY_NONE)); 24988768458SSam Leffler sp->policy = IPSEC_POLICY_NONE; 25088768458SSam Leffler } 251422e4f5bSSam Leffler key_addref(sp); 25288768458SSam Leffler 25388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 25488768458SSam Leffler printf("DP key_allocsp_default returns SP:%p (%u)\n", 25588768458SSam Leffler sp, sp->refcnt)); 25688768458SSam Leffler return sp; 25788768458SSam Leffler } 25888768458SSam Leffler #define KEY_ALLOCSP_DEFAULT() \ 25988768458SSam Leffler key_allocsp_default(__FILE__, __LINE__) 26088768458SSam Leffler 26188768458SSam Leffler /* 26288768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 26388768458SSam Leffler * and return a pointer to SP. 26488768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 26588768458SSam Leffler * 0 : bypass 26688768458SSam Leffler * EACCES : discard packet. 26788768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 26888768458SSam Leffler * others : error occured. 26988768458SSam Leffler * others: a pointer to SP 27088768458SSam Leffler * 27188768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 27288768458SSam Leffler */ 27388768458SSam Leffler struct secpolicy * 27488768458SSam Leffler ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) 27588768458SSam Leffler { 27688768458SSam Leffler struct secpolicy *sp; 27788768458SSam Leffler 2789ffa9677SSam Leffler IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); 2799ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 2809ffa9677SSam Leffler ("invalid direction %u", dir)); 28188768458SSam Leffler 28288768458SSam Leffler sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); 28388768458SSam Leffler if (sp == NULL) /*XXX????*/ 28488768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 2859ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 28688768458SSam Leffler return sp; 28788768458SSam Leffler } 28888768458SSam Leffler 28988768458SSam Leffler /* 29088768458SSam Leffler * For OUTBOUND packet having a socket. Searching SPD for packet, 29188768458SSam Leffler * and return a pointer to SP. 29288768458SSam Leffler * OUT: NULL: no apropreate SP found, the following value is set to error. 29388768458SSam Leffler * 0 : bypass 29488768458SSam Leffler * EACCES : discard packet. 29588768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 29688768458SSam Leffler * others : error occured. 29788768458SSam Leffler * others: a pointer to SP 29888768458SSam Leffler * 29988768458SSam Leffler * NOTE: IPv6 mapped adddress concern is implemented here. 30088768458SSam Leffler */ 30188768458SSam Leffler struct secpolicy * 30288768458SSam Leffler ipsec_getpolicybysock(m, dir, inp, error) 30388768458SSam Leffler struct mbuf *m; 30488768458SSam Leffler u_int dir; 30588768458SSam Leffler struct inpcb *inp; 30688768458SSam Leffler int *error; 30788768458SSam Leffler { 30888768458SSam Leffler struct inpcbpolicy *pcbsp = NULL; 30988768458SSam Leffler struct secpolicy *currsp = NULL; /* policy on socket */ 31088768458SSam Leffler struct secpolicy *sp; 31188768458SSam Leffler 3129ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 3139ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inpcb")); 3149ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 3159ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 3169ffa9677SSam Leffler ("invalid direction %u", dir)); 31788768458SSam Leffler 31888768458SSam Leffler /* set spidx in pcb */ 3199c3309d1SJonathan Lemon if (inp->inp_vflag & INP_IPV6PROTO) { 320595064e8SSam Leffler #ifdef INET6 32188768458SSam Leffler *error = ipsec6_setspidx_in6pcb(m, inp); 32288768458SSam Leffler pcbsp = inp->in6p_sp; 323595064e8SSam Leffler #else 324595064e8SSam Leffler *error = EINVAL; /* should not happen */ 325595064e8SSam Leffler #endif 3269c3309d1SJonathan Lemon } else { 3279c3309d1SJonathan Lemon *error = ipsec4_setspidx_inpcb(m, inp); 3289c3309d1SJonathan Lemon pcbsp = inp->inp_sp; 32988768458SSam Leffler } 33088768458SSam Leffler if (*error) 33188768458SSam Leffler return NULL; 33288768458SSam Leffler 3339ffa9677SSam Leffler IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); 33488768458SSam Leffler switch (dir) { 33588768458SSam Leffler case IPSEC_DIR_INBOUND: 33688768458SSam Leffler currsp = pcbsp->sp_in; 33788768458SSam Leffler break; 33888768458SSam Leffler case IPSEC_DIR_OUTBOUND: 33988768458SSam Leffler currsp = pcbsp->sp_out; 34088768458SSam Leffler break; 34188768458SSam Leffler } 3429ffa9677SSam Leffler IPSEC_ASSERT(currsp != NULL, ("null currsp")); 34388768458SSam Leffler 34488768458SSam Leffler if (pcbsp->priv) { /* when privilieged socket */ 34588768458SSam Leffler switch (currsp->policy) { 34688768458SSam Leffler case IPSEC_POLICY_BYPASS: 34788768458SSam Leffler case IPSEC_POLICY_IPSEC: 348422e4f5bSSam Leffler key_addref(currsp); 34988768458SSam Leffler sp = currsp; 35088768458SSam Leffler break; 35188768458SSam Leffler 35288768458SSam Leffler case IPSEC_POLICY_ENTRUST: 35388768458SSam Leffler /* look for a policy in SPD */ 35488768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 35588768458SSam Leffler if (sp == NULL) /* no SP found */ 35688768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 35788768458SSam Leffler break; 35888768458SSam Leffler 35988768458SSam Leffler default: 3609ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", 3619ffa9677SSam Leffler __func__, currsp->policy)); 36288768458SSam Leffler *error = EINVAL; 36388768458SSam Leffler return NULL; 36488768458SSam Leffler } 36588768458SSam Leffler } else { /* unpriv, SPD has policy */ 36688768458SSam Leffler sp = KEY_ALLOCSP(&currsp->spidx, dir); 36788768458SSam Leffler if (sp == NULL) { /* no SP found */ 36888768458SSam Leffler switch (currsp->policy) { 36988768458SSam Leffler case IPSEC_POLICY_BYPASS: 3709ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Illegal policy for " 3719ffa9677SSam Leffler "non-priviliged defined %d\n", 3729ffa9677SSam Leffler __func__, currsp->policy)); 37388768458SSam Leffler *error = EINVAL; 37488768458SSam Leffler return NULL; 37588768458SSam Leffler 37688768458SSam Leffler case IPSEC_POLICY_ENTRUST: 37788768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 37888768458SSam Leffler break; 37988768458SSam Leffler 38088768458SSam Leffler case IPSEC_POLICY_IPSEC: 381422e4f5bSSam Leffler key_addref(currsp); 38288768458SSam Leffler sp = currsp; 38388768458SSam Leffler break; 38488768458SSam Leffler 38588768458SSam Leffler default: 3869ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: Invalid policy for " 3879ffa9677SSam Leffler "PCB %d\n", __func__, currsp->policy)); 38888768458SSam Leffler *error = EINVAL; 38988768458SSam Leffler return NULL; 39088768458SSam Leffler } 39188768458SSam Leffler } 39288768458SSam Leffler } 3939ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, 3949ffa9677SSam Leffler ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); 39588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 3969ffa9677SSam Leffler printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", 3979ffa9677SSam Leffler __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); 39888768458SSam Leffler return sp; 39988768458SSam Leffler } 40088768458SSam Leffler 40188768458SSam Leffler /* 40288768458SSam Leffler * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, 40388768458SSam Leffler * and return a pointer to SP. 40488768458SSam Leffler * OUT: positive: a pointer to the entry for security policy leaf matched. 40588768458SSam Leffler * NULL: no apropreate SP found, the following value is set to error. 40688768458SSam Leffler * 0 : bypass 40788768458SSam Leffler * EACCES : discard packet. 40888768458SSam Leffler * ENOENT : ipsec_acquire() in progress, maybe. 40988768458SSam Leffler * others : error occured. 41088768458SSam Leffler */ 41188768458SSam Leffler struct secpolicy * 41288768458SSam Leffler ipsec_getpolicybyaddr(m, dir, flag, error) 41388768458SSam Leffler struct mbuf *m; 41488768458SSam Leffler u_int dir; 41588768458SSam Leffler int flag; 41688768458SSam Leffler int *error; 41788768458SSam Leffler { 41888768458SSam Leffler struct secpolicyindex spidx; 41988768458SSam Leffler struct secpolicy *sp; 42088768458SSam Leffler 4219ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 4229ffa9677SSam Leffler IPSEC_ASSERT(error != NULL, ("null error")); 4239ffa9677SSam Leffler IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, 4249ffa9677SSam Leffler ("invalid direction %u", dir)); 42588768458SSam Leffler 42688768458SSam Leffler sp = NULL; 42788768458SSam Leffler if (key_havesp(dir)) { 4289d5abbddSJens Schweikhardt /* Make an index to look for a policy. */ 42988768458SSam Leffler *error = ipsec_setspidx(m, &spidx, 43088768458SSam Leffler (flag & IP_FORWARDING) ? 0 : 1); 43188768458SSam Leffler if (*error != 0) { 4329ffa9677SSam Leffler DPRINTF(("%s: setpidx failed, dir %u flag %u\n", 4339ffa9677SSam Leffler __func__, dir, flag)); 43488768458SSam Leffler return NULL; 43588768458SSam Leffler } 43688768458SSam Leffler spidx.dir = dir; 43788768458SSam Leffler 43888768458SSam Leffler sp = KEY_ALLOCSP(&spidx, dir); 43988768458SSam Leffler } 44088768458SSam Leffler if (sp == NULL) /* no SP found, use system default */ 44188768458SSam Leffler sp = KEY_ALLOCSP_DEFAULT(); 4429ffa9677SSam Leffler IPSEC_ASSERT(sp != NULL, ("null SP")); 44388768458SSam Leffler return sp; 44488768458SSam Leffler } 44588768458SSam Leffler 44688768458SSam Leffler struct secpolicy * 44788768458SSam Leffler ipsec4_checkpolicy(m, dir, flag, error, inp) 44888768458SSam Leffler struct mbuf *m; 44988768458SSam Leffler u_int dir, flag; 45088768458SSam Leffler int *error; 45188768458SSam Leffler struct inpcb *inp; 45288768458SSam Leffler { 45388768458SSam Leffler struct secpolicy *sp; 45488768458SSam Leffler 45588768458SSam Leffler *error = 0; 45688768458SSam Leffler if (inp == NULL) 45788768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, flag, error); 45888768458SSam Leffler else 45988768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, error); 46088768458SSam Leffler if (sp == NULL) { 4619ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); 462603724d3SBjoern A. Zeeb V_ipsec4stat.ips_out_inval++; 46388768458SSam Leffler return NULL; 46488768458SSam Leffler } 4659ffa9677SSam Leffler IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); 46688768458SSam Leffler switch (sp->policy) { 46788768458SSam Leffler case IPSEC_POLICY_ENTRUST: 46888768458SSam Leffler default: 4699ffa9677SSam Leffler printf("%s: invalid policy %u\n", __func__, sp->policy); 47088768458SSam Leffler /* fall thru... */ 47188768458SSam Leffler case IPSEC_POLICY_DISCARD: 472603724d3SBjoern A. Zeeb V_ipsec4stat.ips_out_polvio++; 47388768458SSam Leffler *error = -EINVAL; /* packet is discarded by caller */ 47488768458SSam Leffler break; 47588768458SSam Leffler case IPSEC_POLICY_BYPASS: 47688768458SSam Leffler case IPSEC_POLICY_NONE: 47788768458SSam Leffler KEY_FREESP(&sp); 47888768458SSam Leffler sp = NULL; /* NB: force NULL result */ 47988768458SSam Leffler break; 48088768458SSam Leffler case IPSEC_POLICY_IPSEC: 48188768458SSam Leffler if (sp->req == NULL) /* acquire an SA */ 48288768458SSam Leffler *error = key_spdacquire(sp); 48388768458SSam Leffler break; 48488768458SSam Leffler } 48588768458SSam Leffler if (*error != 0) { 48688768458SSam Leffler KEY_FREESP(&sp); 48788768458SSam Leffler sp = NULL; 48888768458SSam Leffler } 48988768458SSam Leffler return sp; 49088768458SSam Leffler } 49188768458SSam Leffler 49288768458SSam Leffler static int 49388768458SSam Leffler ipsec4_setspidx_inpcb(m, pcb) 49488768458SSam Leffler struct mbuf *m; 49588768458SSam Leffler struct inpcb *pcb; 49688768458SSam Leffler { 49788768458SSam Leffler int error; 49888768458SSam Leffler 4999ffa9677SSam Leffler IPSEC_ASSERT(pcb != NULL, ("null pcb")); 5009ffa9677SSam Leffler IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); 5019ffa9677SSam Leffler IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, 5029ffa9677SSam Leffler ("null sp_in || sp_out")); 50388768458SSam Leffler 50488768458SSam Leffler error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1); 50588768458SSam Leffler if (error == 0) { 50688768458SSam Leffler pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; 50788768458SSam Leffler pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx; 50888768458SSam Leffler pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; 50988768458SSam Leffler } else { 51088768458SSam Leffler bzero(&pcb->inp_sp->sp_in->spidx, 51188768458SSam Leffler sizeof (pcb->inp_sp->sp_in->spidx)); 51288768458SSam Leffler bzero(&pcb->inp_sp->sp_out->spidx, 51388768458SSam Leffler sizeof (pcb->inp_sp->sp_in->spidx)); 51488768458SSam Leffler } 51588768458SSam Leffler return error; 51688768458SSam Leffler } 51788768458SSam Leffler 51888768458SSam Leffler #ifdef INET6 51988768458SSam Leffler static int 52088768458SSam Leffler ipsec6_setspidx_in6pcb(m, pcb) 52188768458SSam Leffler struct mbuf *m; 52288768458SSam Leffler struct in6pcb *pcb; 52388768458SSam Leffler { 52488768458SSam Leffler struct secpolicyindex *spidx; 52588768458SSam Leffler int error; 52688768458SSam Leffler 5279ffa9677SSam Leffler IPSEC_ASSERT(pcb != NULL, ("null pcb")); 5289ffa9677SSam Leffler IPSEC_ASSERT(pcb->in6p_sp != NULL, ("null inp_sp")); 5299ffa9677SSam Leffler IPSEC_ASSERT(pcb->in6p_sp->sp_out != NULL && pcb->in6p_sp->sp_in != NULL, 5309ffa9677SSam Leffler ("null sp_in || sp_out")); 53188768458SSam Leffler 53288768458SSam Leffler bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); 53388768458SSam Leffler bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); 53488768458SSam Leffler 53588768458SSam Leffler spidx = &pcb->in6p_sp->sp_in->spidx; 53688768458SSam Leffler error = ipsec_setspidx(m, spidx, 1); 53788768458SSam Leffler if (error) 53888768458SSam Leffler goto bad; 53988768458SSam Leffler spidx->dir = IPSEC_DIR_INBOUND; 54088768458SSam Leffler 54188768458SSam Leffler spidx = &pcb->in6p_sp->sp_out->spidx; 54288768458SSam Leffler error = ipsec_setspidx(m, spidx, 1); 54388768458SSam Leffler if (error) 54488768458SSam Leffler goto bad; 54588768458SSam Leffler spidx->dir = IPSEC_DIR_OUTBOUND; 54688768458SSam Leffler 54788768458SSam Leffler return 0; 54888768458SSam Leffler 54988768458SSam Leffler bad: 55088768458SSam Leffler bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); 55188768458SSam Leffler bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); 55288768458SSam Leffler return error; 55388768458SSam Leffler } 55488768458SSam Leffler #endif 55588768458SSam Leffler 55688768458SSam Leffler /* 55788768458SSam Leffler * configure security policy index (src/dst/proto/sport/dport) 55888768458SSam Leffler * by looking at the content of mbuf. 55988768458SSam Leffler * the caller is responsible for error recovery (like clearing up spidx). 56088768458SSam Leffler */ 56188768458SSam Leffler static int 56288768458SSam Leffler ipsec_setspidx(m, spidx, needport) 56388768458SSam Leffler struct mbuf *m; 56488768458SSam Leffler struct secpolicyindex *spidx; 56588768458SSam Leffler int needport; 56688768458SSam Leffler { 56788768458SSam Leffler struct ip *ip = NULL; 56888768458SSam Leffler struct ip ipbuf; 56988768458SSam Leffler u_int v; 57088768458SSam Leffler struct mbuf *n; 57188768458SSam Leffler int len; 57288768458SSam Leffler int error; 57388768458SSam Leffler 5749ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 57588768458SSam Leffler 57688768458SSam Leffler /* 57788768458SSam Leffler * validate m->m_pkthdr.len. we see incorrect length if we 57888768458SSam Leffler * mistakenly call this function with inconsistent mbuf chain 57988768458SSam Leffler * (like 4.4BSD tcp/udp processing). XXX should we panic here? 58088768458SSam Leffler */ 58188768458SSam Leffler len = 0; 58288768458SSam Leffler for (n = m; n; n = n->m_next) 58388768458SSam Leffler len += n->m_len; 58488768458SSam Leffler if (m->m_pkthdr.len != len) { 58588768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5869ffa9677SSam Leffler printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", 5879ffa9677SSam Leffler __func__, len, m->m_pkthdr.len)); 58888768458SSam Leffler return EINVAL; 58988768458SSam Leffler } 59088768458SSam Leffler 59188768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip)) { 59288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 5939ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v4), ignored.\n", 5949ffa9677SSam Leffler __func__, m->m_pkthdr.len)); 59588768458SSam Leffler return EINVAL; 59688768458SSam Leffler } 59788768458SSam Leffler 59888768458SSam Leffler if (m->m_len >= sizeof(*ip)) 59988768458SSam Leffler ip = mtod(m, struct ip *); 60088768458SSam Leffler else { 60188768458SSam Leffler m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); 60288768458SSam Leffler ip = &ipbuf; 60388768458SSam Leffler } 60488768458SSam Leffler #ifdef _IP_VHL 60588768458SSam Leffler v = _IP_VHL_V(ip->ip_vhl); 60688768458SSam Leffler #else 60788768458SSam Leffler v = ip->ip_v; 60888768458SSam Leffler #endif 60988768458SSam Leffler switch (v) { 61088768458SSam Leffler case 4: 61188768458SSam Leffler error = ipsec4_setspidx_ipaddr(m, spidx); 61288768458SSam Leffler if (error) 61388768458SSam Leffler return error; 61488768458SSam Leffler ipsec4_get_ulp(m, spidx, needport); 61588768458SSam Leffler return 0; 61688768458SSam Leffler #ifdef INET6 61788768458SSam Leffler case 6: 61888768458SSam Leffler if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { 61988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6209ffa9677SSam Leffler printf("%s: pkthdr len(%d) too small (v6), " 6219ffa9677SSam Leffler "ignored\n", __func__, m->m_pkthdr.len)); 62288768458SSam Leffler return EINVAL; 62388768458SSam Leffler } 62488768458SSam Leffler error = ipsec6_setspidx_ipaddr(m, spidx); 62588768458SSam Leffler if (error) 62688768458SSam Leffler return error; 62788768458SSam Leffler ipsec6_get_ulp(m, spidx, needport); 62888768458SSam Leffler return 0; 62988768458SSam Leffler #endif 63088768458SSam Leffler default: 63188768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 6329ffa9677SSam Leffler printf("%s: " "unknown IP version %u, ignored.\n", 6339ffa9677SSam Leffler __func__, v)); 63488768458SSam Leffler return EINVAL; 63588768458SSam Leffler } 63688768458SSam Leffler } 63788768458SSam Leffler 63888768458SSam Leffler static void 63988768458SSam Leffler ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) 64088768458SSam Leffler { 64188768458SSam Leffler u_int8_t nxt; 64288768458SSam Leffler int off; 64388768458SSam Leffler 64488768458SSam Leffler /* sanity check */ 6459ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 6469ffa9677SSam Leffler IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); 64788768458SSam Leffler 64888768458SSam Leffler /* NB: ip_input() flips it into host endian XXX need more checking */ 64988768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 65088768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 65188768458SSam Leffler if (ip->ip_off & (IP_MF | IP_OFFMASK)) 65288768458SSam Leffler goto done; 65388768458SSam Leffler #ifdef _IP_VHL 65488768458SSam Leffler off = _IP_VHL_HL(ip->ip_vhl) << 2; 65588768458SSam Leffler #else 65688768458SSam Leffler off = ip->ip_hl << 2; 65788768458SSam Leffler #endif 65888768458SSam Leffler nxt = ip->ip_p; 65988768458SSam Leffler } else { 66088768458SSam Leffler struct ip ih; 66188768458SSam Leffler 66288768458SSam Leffler m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); 66388768458SSam Leffler if (ih.ip_off & (IP_MF | IP_OFFMASK)) 66488768458SSam Leffler goto done; 66588768458SSam Leffler #ifdef _IP_VHL 66688768458SSam Leffler off = _IP_VHL_HL(ih.ip_vhl) << 2; 66788768458SSam Leffler #else 66888768458SSam Leffler off = ih.ip_hl << 2; 66988768458SSam Leffler #endif 67088768458SSam Leffler nxt = ih.ip_p; 67188768458SSam Leffler } 67288768458SSam Leffler 67388768458SSam Leffler while (off < m->m_pkthdr.len) { 67488768458SSam Leffler struct ip6_ext ip6e; 67588768458SSam Leffler struct tcphdr th; 67688768458SSam Leffler struct udphdr uh; 67788768458SSam Leffler 67888768458SSam Leffler switch (nxt) { 67988768458SSam Leffler case IPPROTO_TCP: 68088768458SSam Leffler spidx->ul_proto = nxt; 68188768458SSam Leffler if (!needport) 68288768458SSam Leffler goto done_proto; 68388768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 68488768458SSam Leffler goto done; 68588768458SSam Leffler m_copydata(m, off, sizeof (th), (caddr_t) &th); 68688768458SSam Leffler spidx->src.sin.sin_port = th.th_sport; 68788768458SSam Leffler spidx->dst.sin.sin_port = th.th_dport; 68888768458SSam Leffler return; 68988768458SSam Leffler case IPPROTO_UDP: 69088768458SSam Leffler spidx->ul_proto = nxt; 69188768458SSam Leffler if (!needport) 69288768458SSam Leffler goto done_proto; 69388768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 69488768458SSam Leffler goto done; 69588768458SSam Leffler m_copydata(m, off, sizeof (uh), (caddr_t) &uh); 69688768458SSam Leffler spidx->src.sin.sin_port = uh.uh_sport; 69788768458SSam Leffler spidx->dst.sin.sin_port = uh.uh_dport; 69888768458SSam Leffler return; 69988768458SSam Leffler case IPPROTO_AH: 700afa3570dSSam Leffler if (off + sizeof(ip6e) > m->m_pkthdr.len) 70188768458SSam Leffler goto done; 70288768458SSam Leffler /* XXX sigh, this works but is totally bogus */ 70388768458SSam Leffler m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); 70488768458SSam Leffler off += (ip6e.ip6e_len + 2) << 2; 70588768458SSam Leffler nxt = ip6e.ip6e_nxt; 70688768458SSam Leffler break; 70788768458SSam Leffler case IPPROTO_ICMP: 70888768458SSam Leffler default: 70988768458SSam Leffler /* XXX intermediate headers??? */ 71088768458SSam Leffler spidx->ul_proto = nxt; 71188768458SSam Leffler goto done_proto; 71288768458SSam Leffler } 71388768458SSam Leffler } 71488768458SSam Leffler done: 71588768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 71688768458SSam Leffler done_proto: 71788768458SSam Leffler spidx->src.sin.sin_port = IPSEC_PORT_ANY; 71888768458SSam Leffler spidx->dst.sin.sin_port = IPSEC_PORT_ANY; 71988768458SSam Leffler } 72088768458SSam Leffler 72188768458SSam Leffler /* assumes that m is sane */ 72288768458SSam Leffler static int 72388768458SSam Leffler ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) 72488768458SSam Leffler { 72588768458SSam Leffler static const struct sockaddr_in template = { 72688768458SSam Leffler sizeof (struct sockaddr_in), 72788768458SSam Leffler AF_INET, 72888768458SSam Leffler 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 72988768458SSam Leffler }; 73088768458SSam Leffler 73188768458SSam Leffler spidx->src.sin = template; 73288768458SSam Leffler spidx->dst.sin = template; 73388768458SSam Leffler 73488768458SSam Leffler if (m->m_len < sizeof (struct ip)) { 73588768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_src), 73688768458SSam Leffler sizeof (struct in_addr), 73788768458SSam Leffler (caddr_t) &spidx->src.sin.sin_addr); 73888768458SSam Leffler m_copydata(m, offsetof(struct ip, ip_dst), 73988768458SSam Leffler sizeof (struct in_addr), 74088768458SSam Leffler (caddr_t) &spidx->dst.sin.sin_addr); 74188768458SSam Leffler } else { 74288768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 74388768458SSam Leffler spidx->src.sin.sin_addr = ip->ip_src; 74488768458SSam Leffler spidx->dst.sin.sin_addr = ip->ip_dst; 74588768458SSam Leffler } 74688768458SSam Leffler 74788768458SSam Leffler spidx->prefs = sizeof(struct in_addr) << 3; 74888768458SSam Leffler spidx->prefd = sizeof(struct in_addr) << 3; 74988768458SSam Leffler 75088768458SSam Leffler return 0; 75188768458SSam Leffler } 75288768458SSam Leffler 75388768458SSam Leffler #ifdef INET6 75488768458SSam Leffler static void 75588768458SSam Leffler ipsec6_get_ulp(m, spidx, needport) 75688768458SSam Leffler struct mbuf *m; 75788768458SSam Leffler struct secpolicyindex *spidx; 75888768458SSam Leffler int needport; 75988768458SSam Leffler { 76088768458SSam Leffler int off, nxt; 76188768458SSam Leffler struct tcphdr th; 76288768458SSam Leffler struct udphdr uh; 7630e3c2be4SBjoern A. Zeeb struct icmp6_hdr ih; 76488768458SSam Leffler 76588768458SSam Leffler /* sanity check */ 76688768458SSam Leffler if (m == NULL) 7679ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 76888768458SSam Leffler 76988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 7709ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(m)); 77188768458SSam Leffler 77288768458SSam Leffler /* set default */ 77388768458SSam Leffler spidx->ul_proto = IPSEC_ULPROTO_ANY; 77488768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; 77588768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; 77688768458SSam Leffler 77788768458SSam Leffler nxt = -1; 77888768458SSam Leffler off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); 77988768458SSam Leffler if (off < 0 || m->m_pkthdr.len < off) 78088768458SSam Leffler return; 78188768458SSam Leffler 78288768458SSam Leffler switch (nxt) { 78388768458SSam Leffler case IPPROTO_TCP: 78488768458SSam Leffler spidx->ul_proto = nxt; 78588768458SSam Leffler if (!needport) 78688768458SSam Leffler break; 78788768458SSam Leffler if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) 78888768458SSam Leffler break; 78988768458SSam Leffler m_copydata(m, off, sizeof(th), (caddr_t)&th); 79088768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; 79188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; 79288768458SSam Leffler break; 79388768458SSam Leffler case IPPROTO_UDP: 79488768458SSam Leffler spidx->ul_proto = nxt; 79588768458SSam Leffler if (!needport) 79688768458SSam Leffler break; 79788768458SSam Leffler if (off + sizeof(struct udphdr) > m->m_pkthdr.len) 79888768458SSam Leffler break; 79988768458SSam Leffler m_copydata(m, off, sizeof(uh), (caddr_t)&uh); 80088768458SSam Leffler ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; 80188768458SSam Leffler ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; 80288768458SSam Leffler break; 80388768458SSam Leffler case IPPROTO_ICMPV6: 8040e3c2be4SBjoern A. Zeeb spidx->ul_proto = nxt; 8050e3c2be4SBjoern A. Zeeb if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) 8060e3c2be4SBjoern A. Zeeb break; 8070e3c2be4SBjoern A. Zeeb m_copydata(m, off, sizeof(ih), (caddr_t)&ih); 8080e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->src)->sin6_port = 8090e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_type); 8100e3c2be4SBjoern A. Zeeb ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = 8110e3c2be4SBjoern A. Zeeb htons((uint16_t)ih.icmp6_code); 8120e3c2be4SBjoern A. Zeeb break; 81388768458SSam Leffler default: 81488768458SSam Leffler /* XXX intermediate headers??? */ 81588768458SSam Leffler spidx->ul_proto = nxt; 81688768458SSam Leffler break; 81788768458SSam Leffler } 81888768458SSam Leffler } 81988768458SSam Leffler 82088768458SSam Leffler /* assumes that m is sane */ 82188768458SSam Leffler static int 82288768458SSam Leffler ipsec6_setspidx_ipaddr(m, spidx) 82388768458SSam Leffler struct mbuf *m; 82488768458SSam Leffler struct secpolicyindex *spidx; 82588768458SSam Leffler { 82688768458SSam Leffler struct ip6_hdr *ip6 = NULL; 82788768458SSam Leffler struct ip6_hdr ip6buf; 82888768458SSam Leffler struct sockaddr_in6 *sin6; 82988768458SSam Leffler 83088768458SSam Leffler if (m->m_len >= sizeof(*ip6)) 83188768458SSam Leffler ip6 = mtod(m, struct ip6_hdr *); 83288768458SSam Leffler else { 83388768458SSam Leffler m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 83488768458SSam Leffler ip6 = &ip6buf; 83588768458SSam Leffler } 83688768458SSam Leffler 83788768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->src; 83888768458SSam Leffler bzero(sin6, sizeof(*sin6)); 83988768458SSam Leffler sin6->sin6_family = AF_INET6; 84088768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 84188768458SSam Leffler bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); 84288768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 84388768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 84488768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); 84588768458SSam Leffler } 84688768458SSam Leffler spidx->prefs = sizeof(struct in6_addr) << 3; 84788768458SSam Leffler 84888768458SSam Leffler sin6 = (struct sockaddr_in6 *)&spidx->dst; 84988768458SSam Leffler bzero(sin6, sizeof(*sin6)); 85088768458SSam Leffler sin6->sin6_family = AF_INET6; 85188768458SSam Leffler sin6->sin6_len = sizeof(struct sockaddr_in6); 85288768458SSam Leffler bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); 85388768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 85488768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 85588768458SSam Leffler sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); 85688768458SSam Leffler } 85788768458SSam Leffler spidx->prefd = sizeof(struct in6_addr) << 3; 85888768458SSam Leffler 85988768458SSam Leffler return 0; 86088768458SSam Leffler } 86188768458SSam Leffler #endif 86288768458SSam Leffler 86388768458SSam Leffler static void 86488768458SSam Leffler ipsec_delpcbpolicy(p) 86588768458SSam Leffler struct inpcbpolicy *p; 86688768458SSam Leffler { 8676464079fSSam Leffler free(p, M_IPSEC_INPCB); 86888768458SSam Leffler } 86988768458SSam Leffler 87088768458SSam Leffler /* initialize policy in PCB */ 87188768458SSam Leffler int 87288768458SSam Leffler ipsec_init_policy(so, pcb_sp) 87388768458SSam Leffler struct socket *so; 87488768458SSam Leffler struct inpcbpolicy **pcb_sp; 87588768458SSam Leffler { 87688768458SSam Leffler struct inpcbpolicy *new; 87788768458SSam Leffler 87888768458SSam Leffler /* sanity check. */ 87988768458SSam Leffler if (so == NULL || pcb_sp == NULL) 8809ffa9677SSam Leffler panic("%s: NULL pointer was passed.\n", __func__); 88188768458SSam Leffler 88288768458SSam Leffler new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), 8836464079fSSam Leffler M_IPSEC_INPCB, M_NOWAIT|M_ZERO); 88488768458SSam Leffler if (new == NULL) { 8859ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 88688768458SSam Leffler return ENOBUFS; 88788768458SSam Leffler } 88888768458SSam Leffler 8899ffa9677SSam Leffler new->priv = IPSEC_IS_PRIVILEGED_SO(so); 89088768458SSam Leffler 89188768458SSam Leffler if ((new->sp_in = KEY_NEWSP()) == NULL) { 89288768458SSam Leffler ipsec_delpcbpolicy(new); 89388768458SSam Leffler return ENOBUFS; 89488768458SSam Leffler } 89588768458SSam Leffler new->sp_in->state = IPSEC_SPSTATE_ALIVE; 89688768458SSam Leffler new->sp_in->policy = IPSEC_POLICY_ENTRUST; 89788768458SSam Leffler 89888768458SSam Leffler if ((new->sp_out = KEY_NEWSP()) == NULL) { 89988768458SSam Leffler KEY_FREESP(&new->sp_in); 90088768458SSam Leffler ipsec_delpcbpolicy(new); 90188768458SSam Leffler return ENOBUFS; 90288768458SSam Leffler } 90388768458SSam Leffler new->sp_out->state = IPSEC_SPSTATE_ALIVE; 90488768458SSam Leffler new->sp_out->policy = IPSEC_POLICY_ENTRUST; 90588768458SSam Leffler 90688768458SSam Leffler *pcb_sp = new; 90788768458SSam Leffler 90888768458SSam Leffler return 0; 90988768458SSam Leffler } 91088768458SSam Leffler 91188768458SSam Leffler /* copy old ipsec policy into new */ 91288768458SSam Leffler int 91388768458SSam Leffler ipsec_copy_policy(old, new) 91488768458SSam Leffler struct inpcbpolicy *old, *new; 91588768458SSam Leffler { 91688768458SSam Leffler struct secpolicy *sp; 91788768458SSam Leffler 91888768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_in); 91988768458SSam Leffler if (sp) { 92088768458SSam Leffler KEY_FREESP(&new->sp_in); 92188768458SSam Leffler new->sp_in = sp; 92288768458SSam Leffler } else 92388768458SSam Leffler return ENOBUFS; 92488768458SSam Leffler 92588768458SSam Leffler sp = ipsec_deepcopy_policy(old->sp_out); 92688768458SSam Leffler if (sp) { 92788768458SSam Leffler KEY_FREESP(&new->sp_out); 92888768458SSam Leffler new->sp_out = sp; 92988768458SSam Leffler } else 93088768458SSam Leffler return ENOBUFS; 93188768458SSam Leffler 93288768458SSam Leffler new->priv = old->priv; 93388768458SSam Leffler 93488768458SSam Leffler return 0; 93588768458SSam Leffler } 93688768458SSam Leffler 9376464079fSSam Leffler struct ipsecrequest * 9386464079fSSam Leffler ipsec_newisr(void) 9396464079fSSam Leffler { 9406464079fSSam Leffler struct ipsecrequest *p; 9416464079fSSam Leffler 9426464079fSSam Leffler p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); 9436464079fSSam Leffler if (p != NULL) 9449ffa9677SSam Leffler IPSECREQUEST_LOCK_INIT(p); 9456464079fSSam Leffler return p; 9466464079fSSam Leffler } 9476464079fSSam Leffler 9486464079fSSam Leffler void 9496464079fSSam Leffler ipsec_delisr(struct ipsecrequest *p) 9506464079fSSam Leffler { 9519ffa9677SSam Leffler IPSECREQUEST_LOCK_DESTROY(p); 9526464079fSSam Leffler free(p, M_IPSEC_SR); 9536464079fSSam Leffler } 9546464079fSSam Leffler 95588768458SSam Leffler /* deep-copy a policy in PCB */ 95688768458SSam Leffler static struct secpolicy * 95788768458SSam Leffler ipsec_deepcopy_policy(src) 95888768458SSam Leffler struct secpolicy *src; 95988768458SSam Leffler { 96088768458SSam Leffler struct ipsecrequest *newchain = NULL; 96188768458SSam Leffler struct ipsecrequest *p; 96288768458SSam Leffler struct ipsecrequest **q; 96388768458SSam Leffler struct ipsecrequest *r; 96488768458SSam Leffler struct secpolicy *dst; 96588768458SSam Leffler 96688768458SSam Leffler if (src == NULL) 96788768458SSam Leffler return NULL; 96888768458SSam Leffler dst = KEY_NEWSP(); 96988768458SSam Leffler if (dst == NULL) 97088768458SSam Leffler return NULL; 97188768458SSam Leffler 97288768458SSam Leffler /* 97388768458SSam Leffler * deep-copy IPsec request chain. This is required since struct 97488768458SSam Leffler * ipsecrequest is not reference counted. 97588768458SSam Leffler */ 97688768458SSam Leffler q = &newchain; 97788768458SSam Leffler for (p = src->req; p; p = p->next) { 9786464079fSSam Leffler *q = ipsec_newisr(); 97988768458SSam Leffler if (*q == NULL) 98088768458SSam Leffler goto fail; 98188768458SSam Leffler (*q)->saidx.proto = p->saidx.proto; 98288768458SSam Leffler (*q)->saidx.mode = p->saidx.mode; 98388768458SSam Leffler (*q)->level = p->level; 98488768458SSam Leffler (*q)->saidx.reqid = p->saidx.reqid; 98588768458SSam Leffler 98688768458SSam Leffler bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); 98788768458SSam Leffler bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); 98888768458SSam Leffler 98988768458SSam Leffler (*q)->sp = dst; 99088768458SSam Leffler 99188768458SSam Leffler q = &((*q)->next); 99288768458SSam Leffler } 99388768458SSam Leffler 99488768458SSam Leffler dst->req = newchain; 99588768458SSam Leffler dst->state = src->state; 99688768458SSam Leffler dst->policy = src->policy; 99788768458SSam Leffler /* do not touch the refcnt fields */ 99888768458SSam Leffler 99988768458SSam Leffler return dst; 100088768458SSam Leffler 100188768458SSam Leffler fail: 100288768458SSam Leffler for (p = newchain; p; p = r) { 100388768458SSam Leffler r = p->next; 10046464079fSSam Leffler ipsec_delisr(p); 100588768458SSam Leffler p = NULL; 100688768458SSam Leffler } 100788768458SSam Leffler return NULL; 100888768458SSam Leffler } 100988768458SSam Leffler 101088768458SSam Leffler /* set policy and ipsec request if present. */ 101188768458SSam Leffler static int 1012c26fe973SBjoern A. Zeeb ipsec_set_policy(pcb_sp, optname, request, len, cred) 101388768458SSam Leffler struct secpolicy **pcb_sp; 101488768458SSam Leffler int optname; 101588768458SSam Leffler caddr_t request; 101688768458SSam Leffler size_t len; 1017c26fe973SBjoern A. Zeeb struct ucred *cred; 101888768458SSam Leffler { 101988768458SSam Leffler struct sadb_x_policy *xpl; 102088768458SSam Leffler struct secpolicy *newsp = NULL; 102188768458SSam Leffler int error; 102288768458SSam Leffler 102388768458SSam Leffler /* sanity check. */ 102488768458SSam Leffler if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) 102588768458SSam Leffler return EINVAL; 102688768458SSam Leffler if (len < sizeof(*xpl)) 102788768458SSam Leffler return EINVAL; 102888768458SSam Leffler xpl = (struct sadb_x_policy *)request; 102988768458SSam Leffler 103088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10319ffa9677SSam Leffler printf("%s: passed policy\n", __func__); 103288768458SSam Leffler kdebug_sadb_x_policy((struct sadb_ext *)xpl)); 103388768458SSam Leffler 103488768458SSam Leffler /* check policy type */ 103588768458SSam Leffler /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ 103688768458SSam Leffler if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD 103788768458SSam Leffler || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) 103888768458SSam Leffler return EINVAL; 103988768458SSam Leffler 104088768458SSam Leffler /* check privileged socket */ 1041c26fe973SBjoern A. Zeeb if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { 1042c26fe973SBjoern A. Zeeb error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); 1043c26fe973SBjoern A. Zeeb if (error) 104488768458SSam Leffler return EACCES; 1045c26fe973SBjoern A. Zeeb } 104688768458SSam Leffler 104788768458SSam Leffler /* allocation new SP entry */ 104888768458SSam Leffler if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) 104988768458SSam Leffler return error; 105088768458SSam Leffler 105188768458SSam Leffler newsp->state = IPSEC_SPSTATE_ALIVE; 105288768458SSam Leffler 105388768458SSam Leffler /* clear old SP and set new SP */ 105488768458SSam Leffler KEY_FREESP(pcb_sp); 105588768458SSam Leffler *pcb_sp = newsp; 105688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10579ffa9677SSam Leffler printf("%s: new policy\n", __func__); 105888768458SSam Leffler kdebug_secpolicy(newsp)); 105988768458SSam Leffler 106088768458SSam Leffler return 0; 106188768458SSam Leffler } 106288768458SSam Leffler 106388768458SSam Leffler static int 106488768458SSam Leffler ipsec_get_policy(pcb_sp, mp) 106588768458SSam Leffler struct secpolicy *pcb_sp; 106688768458SSam Leffler struct mbuf **mp; 106788768458SSam Leffler { 106888768458SSam Leffler 106988768458SSam Leffler /* sanity check. */ 107088768458SSam Leffler if (pcb_sp == NULL || mp == NULL) 107188768458SSam Leffler return EINVAL; 107288768458SSam Leffler 107388768458SSam Leffler *mp = key_sp2msg(pcb_sp); 107488768458SSam Leffler if (!*mp) { 10759ffa9677SSam Leffler ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); 107688768458SSam Leffler return ENOBUFS; 107788768458SSam Leffler } 107888768458SSam Leffler 107988768458SSam Leffler (*mp)->m_type = MT_DATA; 108088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 10819ffa9677SSam Leffler printf("%s:\n", __func__); kdebug_mbuf(*mp)); 108288768458SSam Leffler 108388768458SSam Leffler return 0; 108488768458SSam Leffler } 108588768458SSam Leffler 108688768458SSam Leffler int 1087c26fe973SBjoern A. Zeeb ipsec4_set_policy(inp, optname, request, len, cred) 108888768458SSam Leffler struct inpcb *inp; 108988768458SSam Leffler int optname; 109088768458SSam Leffler caddr_t request; 109188768458SSam Leffler size_t len; 1092c26fe973SBjoern A. Zeeb struct ucred *cred; 109388768458SSam Leffler { 109488768458SSam Leffler struct sadb_x_policy *xpl; 109588768458SSam Leffler struct secpolicy **pcb_sp; 109688768458SSam Leffler 109788768458SSam Leffler /* sanity check. */ 109888768458SSam Leffler if (inp == NULL || request == NULL) 109988768458SSam Leffler return EINVAL; 110088768458SSam Leffler if (len < sizeof(*xpl)) 110188768458SSam Leffler return EINVAL; 110288768458SSam Leffler xpl = (struct sadb_x_policy *)request; 110388768458SSam Leffler 110488768458SSam Leffler /* select direction */ 110588768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 110688768458SSam Leffler case IPSEC_DIR_INBOUND: 110788768458SSam Leffler pcb_sp = &inp->inp_sp->sp_in; 110888768458SSam Leffler break; 110988768458SSam Leffler case IPSEC_DIR_OUTBOUND: 111088768458SSam Leffler pcb_sp = &inp->inp_sp->sp_out; 111188768458SSam Leffler break; 111288768458SSam Leffler default: 11139ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 111488768458SSam Leffler xpl->sadb_x_policy_dir)); 111588768458SSam Leffler return EINVAL; 111688768458SSam Leffler } 111788768458SSam Leffler 1118c26fe973SBjoern A. Zeeb return ipsec_set_policy(pcb_sp, optname, request, len, cred); 111988768458SSam Leffler } 112088768458SSam Leffler 112188768458SSam Leffler int 112288768458SSam Leffler ipsec4_get_policy(inp, request, len, mp) 112388768458SSam Leffler struct inpcb *inp; 112488768458SSam Leffler caddr_t request; 112588768458SSam Leffler size_t len; 112688768458SSam Leffler struct mbuf **mp; 112788768458SSam Leffler { 112888768458SSam Leffler struct sadb_x_policy *xpl; 112988768458SSam Leffler struct secpolicy *pcb_sp; 113088768458SSam Leffler 113188768458SSam Leffler /* sanity check. */ 113288768458SSam Leffler if (inp == NULL || request == NULL || mp == NULL) 113388768458SSam Leffler return EINVAL; 11349ffa9677SSam Leffler IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); 113588768458SSam Leffler if (len < sizeof(*xpl)) 113688768458SSam Leffler return EINVAL; 113788768458SSam Leffler xpl = (struct sadb_x_policy *)request; 113888768458SSam Leffler 113988768458SSam Leffler /* select direction */ 114088768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 114188768458SSam Leffler case IPSEC_DIR_INBOUND: 114288768458SSam Leffler pcb_sp = inp->inp_sp->sp_in; 114388768458SSam Leffler break; 114488768458SSam Leffler case IPSEC_DIR_OUTBOUND: 114588768458SSam Leffler pcb_sp = inp->inp_sp->sp_out; 114688768458SSam Leffler break; 114788768458SSam Leffler default: 11489ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 114988768458SSam Leffler xpl->sadb_x_policy_dir)); 115088768458SSam Leffler return EINVAL; 115188768458SSam Leffler } 115288768458SSam Leffler 115388768458SSam Leffler return ipsec_get_policy(pcb_sp, mp); 115488768458SSam Leffler } 115588768458SSam Leffler 115688768458SSam Leffler /* delete policy in PCB */ 115788768458SSam Leffler int 115888768458SSam Leffler ipsec4_delete_pcbpolicy(inp) 115988768458SSam Leffler struct inpcb *inp; 116088768458SSam Leffler { 11619ffa9677SSam Leffler IPSEC_ASSERT(inp != NULL, ("null inp")); 116288768458SSam Leffler 116388768458SSam Leffler if (inp->inp_sp == NULL) 116488768458SSam Leffler return 0; 116588768458SSam Leffler 116688768458SSam Leffler if (inp->inp_sp->sp_in != NULL) 116788768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_in); 116888768458SSam Leffler 116988768458SSam Leffler if (inp->inp_sp->sp_out != NULL) 117088768458SSam Leffler KEY_FREESP(&inp->inp_sp->sp_out); 117188768458SSam Leffler 117288768458SSam Leffler ipsec_delpcbpolicy(inp->inp_sp); 117388768458SSam Leffler inp->inp_sp = NULL; 117488768458SSam Leffler 117588768458SSam Leffler return 0; 117688768458SSam Leffler } 117788768458SSam Leffler 117888768458SSam Leffler #ifdef INET6 117988768458SSam Leffler int 1180c26fe973SBjoern A. Zeeb ipsec6_set_policy(in6p, optname, request, len, cred) 118188768458SSam Leffler struct in6pcb *in6p; 118288768458SSam Leffler int optname; 118388768458SSam Leffler caddr_t request; 118488768458SSam Leffler size_t len; 1185c26fe973SBjoern A. Zeeb struct ucred *cred; 118688768458SSam Leffler { 118788768458SSam Leffler struct sadb_x_policy *xpl; 118888768458SSam Leffler struct secpolicy **pcb_sp; 118988768458SSam Leffler 119088768458SSam Leffler /* sanity check. */ 119188768458SSam Leffler if (in6p == NULL || request == NULL) 119288768458SSam Leffler return EINVAL; 119388768458SSam Leffler if (len < sizeof(*xpl)) 119488768458SSam Leffler return EINVAL; 119588768458SSam Leffler xpl = (struct sadb_x_policy *)request; 119688768458SSam Leffler 119788768458SSam Leffler /* select direction */ 119888768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 119988768458SSam Leffler case IPSEC_DIR_INBOUND: 120088768458SSam Leffler pcb_sp = &in6p->in6p_sp->sp_in; 120188768458SSam Leffler break; 120288768458SSam Leffler case IPSEC_DIR_OUTBOUND: 120388768458SSam Leffler pcb_sp = &in6p->in6p_sp->sp_out; 120488768458SSam Leffler break; 120588768458SSam Leffler default: 12069ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 120788768458SSam Leffler xpl->sadb_x_policy_dir)); 120888768458SSam Leffler return EINVAL; 120988768458SSam Leffler } 121088768458SSam Leffler 1211c26fe973SBjoern A. Zeeb return ipsec_set_policy(pcb_sp, optname, request, len, cred); 121288768458SSam Leffler } 121388768458SSam Leffler 121488768458SSam Leffler int 121588768458SSam Leffler ipsec6_get_policy(in6p, request, len, mp) 121688768458SSam Leffler struct in6pcb *in6p; 121788768458SSam Leffler caddr_t request; 121888768458SSam Leffler size_t len; 121988768458SSam Leffler struct mbuf **mp; 122088768458SSam Leffler { 122188768458SSam Leffler struct sadb_x_policy *xpl; 122288768458SSam Leffler struct secpolicy *pcb_sp; 122388768458SSam Leffler 122488768458SSam Leffler /* sanity check. */ 122588768458SSam Leffler if (in6p == NULL || request == NULL || mp == NULL) 122688768458SSam Leffler return EINVAL; 12279ffa9677SSam Leffler IPSEC_ASSERT(in6p->in6p_sp != NULL, ("null in6p_sp")); 122888768458SSam Leffler if (len < sizeof(*xpl)) 122988768458SSam Leffler return EINVAL; 123088768458SSam Leffler xpl = (struct sadb_x_policy *)request; 123188768458SSam Leffler 123288768458SSam Leffler /* select direction */ 123388768458SSam Leffler switch (xpl->sadb_x_policy_dir) { 123488768458SSam Leffler case IPSEC_DIR_INBOUND: 123588768458SSam Leffler pcb_sp = in6p->in6p_sp->sp_in; 123688768458SSam Leffler break; 123788768458SSam Leffler case IPSEC_DIR_OUTBOUND: 123888768458SSam Leffler pcb_sp = in6p->in6p_sp->sp_out; 123988768458SSam Leffler break; 124088768458SSam Leffler default: 12419ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, 124288768458SSam Leffler xpl->sadb_x_policy_dir)); 124388768458SSam Leffler return EINVAL; 124488768458SSam Leffler } 124588768458SSam Leffler 124688768458SSam Leffler return ipsec_get_policy(pcb_sp, mp); 124788768458SSam Leffler } 124888768458SSam Leffler 124988768458SSam Leffler int 125088768458SSam Leffler ipsec6_delete_pcbpolicy(in6p) 125188768458SSam Leffler struct in6pcb *in6p; 125288768458SSam Leffler { 12539ffa9677SSam Leffler IPSEC_ASSERT(in6p != NULL, ("null in6p")); 125488768458SSam Leffler 125588768458SSam Leffler if (in6p->in6p_sp == NULL) 125688768458SSam Leffler return 0; 125788768458SSam Leffler 125888768458SSam Leffler if (in6p->in6p_sp->sp_in != NULL) 125988768458SSam Leffler KEY_FREESP(&in6p->in6p_sp->sp_in); 126088768458SSam Leffler 126188768458SSam Leffler if (in6p->in6p_sp->sp_out != NULL) 126288768458SSam Leffler KEY_FREESP(&in6p->in6p_sp->sp_out); 126388768458SSam Leffler 126488768458SSam Leffler ipsec_delpcbpolicy(in6p->in6p_sp); 126588768458SSam Leffler in6p->in6p_sp = NULL; 126688768458SSam Leffler 126788768458SSam Leffler return 0; 126888768458SSam Leffler } 126988768458SSam Leffler #endif 127088768458SSam Leffler 127188768458SSam Leffler /* 127288768458SSam Leffler * return current level. 127388768458SSam Leffler * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. 127488768458SSam Leffler */ 127588768458SSam Leffler u_int 127688768458SSam Leffler ipsec_get_reqlevel(isr) 127788768458SSam Leffler struct ipsecrequest *isr; 127888768458SSam Leffler { 127988768458SSam Leffler u_int level = 0; 128088768458SSam Leffler u_int esp_trans_deflev, esp_net_deflev; 128188768458SSam Leffler u_int ah_trans_deflev, ah_net_deflev; 128288768458SSam Leffler 12839ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); 12849ffa9677SSam Leffler IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, 12859ffa9677SSam Leffler ("af family mismatch, src %u, dst %u", 128688768458SSam Leffler isr->sp->spidx.src.sa.sa_family, 128788768458SSam Leffler isr->sp->spidx.dst.sa.sa_family)); 128888768458SSam Leffler 128988768458SSam Leffler /* XXX note that we have ipseclog() expanded here - code sync issue */ 129088768458SSam Leffler #define IPSEC_CHECK_DEFAULT(lev) \ 129188768458SSam Leffler (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ 129288768458SSam Leffler && (lev) != IPSEC_LEVEL_UNIQUE) \ 1293603724d3SBjoern A. Zeeb ? (V_ipsec_debug \ 129488768458SSam Leffler ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ 129588768458SSam Leffler (lev), IPSEC_LEVEL_REQUIRE) \ 129688768458SSam Leffler : 0), \ 129788768458SSam Leffler (lev) = IPSEC_LEVEL_REQUIRE, \ 129888768458SSam Leffler (lev) \ 129988768458SSam Leffler : (lev)) 130088768458SSam Leffler 130188768458SSam Leffler /* set default level */ 130288768458SSam Leffler switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { 130388768458SSam Leffler #ifdef INET 130488768458SSam Leffler case AF_INET: 1305603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); 1306603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); 1307603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); 1308603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); 130988768458SSam Leffler break; 131088768458SSam Leffler #endif 131188768458SSam Leffler #ifdef INET6 131288768458SSam Leffler case AF_INET6: 1313603724d3SBjoern A. Zeeb esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); 1314603724d3SBjoern A. Zeeb esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); 1315603724d3SBjoern A. Zeeb ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); 1316603724d3SBjoern A. Zeeb ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); 131788768458SSam Leffler break; 131888768458SSam Leffler #endif /* INET6 */ 131988768458SSam Leffler default: 13209ffa9677SSam Leffler panic("%s: unknown af %u", 13219ffa9677SSam Leffler __func__, isr->sp->spidx.src.sa.sa_family); 132288768458SSam Leffler } 132388768458SSam Leffler 132488768458SSam Leffler #undef IPSEC_CHECK_DEFAULT 132588768458SSam Leffler 132688768458SSam Leffler /* set level */ 132788768458SSam Leffler switch (isr->level) { 132888768458SSam Leffler case IPSEC_LEVEL_DEFAULT: 132988768458SSam Leffler switch (isr->saidx.proto) { 133088768458SSam Leffler case IPPROTO_ESP: 133188768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 133288768458SSam Leffler level = esp_net_deflev; 133388768458SSam Leffler else 133488768458SSam Leffler level = esp_trans_deflev; 133588768458SSam Leffler break; 133688768458SSam Leffler case IPPROTO_AH: 133788768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) 133888768458SSam Leffler level = ah_net_deflev; 133988768458SSam Leffler else 134088768458SSam Leffler level = ah_trans_deflev; 13418381996eSSam Leffler break; 134288768458SSam Leffler case IPPROTO_IPCOMP: 134388768458SSam Leffler /* 134488768458SSam Leffler * we don't really care, as IPcomp document says that 134588768458SSam Leffler * we shouldn't compress small packets 134688768458SSam Leffler */ 134788768458SSam Leffler level = IPSEC_LEVEL_USE; 134888768458SSam Leffler break; 134988768458SSam Leffler default: 13509ffa9677SSam Leffler panic("%s: Illegal protocol defined %u\n", __func__, 135188768458SSam Leffler isr->saidx.proto); 135288768458SSam Leffler } 135388768458SSam Leffler break; 135488768458SSam Leffler 135588768458SSam Leffler case IPSEC_LEVEL_USE: 135688768458SSam Leffler case IPSEC_LEVEL_REQUIRE: 135788768458SSam Leffler level = isr->level; 135888768458SSam Leffler break; 135988768458SSam Leffler case IPSEC_LEVEL_UNIQUE: 136088768458SSam Leffler level = IPSEC_LEVEL_REQUIRE; 136188768458SSam Leffler break; 136288768458SSam Leffler 136388768458SSam Leffler default: 13649ffa9677SSam Leffler panic("%s: Illegal IPsec level %u\n", __func__, isr->level); 136588768458SSam Leffler } 136688768458SSam Leffler 136788768458SSam Leffler return level; 136888768458SSam Leffler } 136988768458SSam Leffler 137088768458SSam Leffler /* 137188768458SSam Leffler * Check security policy requirements against the actual 137288768458SSam Leffler * packet contents. Return one if the packet should be 137388768458SSam Leffler * reject as "invalid"; otherwiser return zero to have the 137488768458SSam Leffler * packet treated as "valid". 137588768458SSam Leffler * 137688768458SSam Leffler * OUT: 137788768458SSam Leffler * 0: valid 137888768458SSam Leffler * 1: invalid 137988768458SSam Leffler */ 138088768458SSam Leffler int 138188768458SSam Leffler ipsec_in_reject(struct secpolicy *sp, struct mbuf *m) 138288768458SSam Leffler { 138388768458SSam Leffler struct ipsecrequest *isr; 138488768458SSam Leffler int need_auth; 138588768458SSam Leffler 138688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 13879ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 138888768458SSam Leffler 138988768458SSam Leffler /* check policy */ 139088768458SSam Leffler switch (sp->policy) { 139188768458SSam Leffler case IPSEC_POLICY_DISCARD: 139288768458SSam Leffler return 1; 139388768458SSam Leffler case IPSEC_POLICY_BYPASS: 139488768458SSam Leffler case IPSEC_POLICY_NONE: 139588768458SSam Leffler return 0; 139688768458SSam Leffler } 139788768458SSam Leffler 13989ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 13999ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 140088768458SSam Leffler 140188768458SSam Leffler /* XXX should compare policy against ipsec header history */ 140288768458SSam Leffler 140388768458SSam Leffler need_auth = 0; 140488768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 140588768458SSam Leffler if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) 140688768458SSam Leffler continue; 140788768458SSam Leffler switch (isr->saidx.proto) { 140888768458SSam Leffler case IPPROTO_ESP: 140988768458SSam Leffler if ((m->m_flags & M_DECRYPTED) == 0) { 141088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14119ffa9677SSam Leffler printf("%s: ESP m_flags:%x\n", __func__, 141288768458SSam Leffler m->m_flags)); 141388768458SSam Leffler return 1; 141488768458SSam Leffler } 141588768458SSam Leffler 141688768458SSam Leffler if (!need_auth && 141788768458SSam Leffler isr->sav != NULL && 141888768458SSam Leffler isr->sav->tdb_authalgxform != NULL && 141988768458SSam Leffler (m->m_flags & M_AUTHIPDGM) == 0) { 142088768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14219ffa9677SSam Leffler printf("%s: ESP/AH m_flags:%x\n", __func__, 142288768458SSam Leffler m->m_flags)); 142388768458SSam Leffler return 1; 142488768458SSam Leffler } 142588768458SSam Leffler break; 142688768458SSam Leffler case IPPROTO_AH: 142788768458SSam Leffler need_auth = 1; 142888768458SSam Leffler if ((m->m_flags & M_AUTHIPHDR) == 0) { 142988768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DUMP, 14309ffa9677SSam Leffler printf("%s: AH m_flags:%x\n", __func__, 143188768458SSam Leffler m->m_flags)); 143288768458SSam Leffler return 1; 143388768458SSam Leffler } 143488768458SSam Leffler break; 143588768458SSam Leffler case IPPROTO_IPCOMP: 143688768458SSam Leffler /* 143788768458SSam Leffler * we don't really care, as IPcomp document 143888768458SSam Leffler * says that we shouldn't compress small 143988768458SSam Leffler * packets, IPComp policy should always be 144088768458SSam Leffler * treated as being in "use" level. 144188768458SSam Leffler */ 144288768458SSam Leffler break; 144388768458SSam Leffler } 144488768458SSam Leffler } 144588768458SSam Leffler return 0; /* valid */ 144688768458SSam Leffler } 144788768458SSam Leffler 144888768458SSam Leffler /* 144988768458SSam Leffler * Check AH/ESP integrity. 145088768458SSam Leffler * This function is called from tcp_input(), udp_input(), 145188768458SSam Leffler * and {ah,esp}4_input for tunnel mode 145288768458SSam Leffler */ 145388768458SSam Leffler int 145488768458SSam Leffler ipsec4_in_reject(m, inp) 145588768458SSam Leffler struct mbuf *m; 145688768458SSam Leffler struct inpcb *inp; 145788768458SSam Leffler { 145888768458SSam Leffler struct secpolicy *sp; 145988768458SSam Leffler int error; 146088768458SSam Leffler int result; 146188768458SSam Leffler 14629ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 146388768458SSam Leffler 146488768458SSam Leffler /* get SP for this packet. 146588768458SSam Leffler * When we are called from ip_forward(), we call 146688768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 146788768458SSam Leffler */ 146888768458SSam Leffler if (inp == NULL) 146988768458SSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 147088768458SSam Leffler else 147188768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 147288768458SSam Leffler 147388768458SSam Leffler if (sp != NULL) { 147488768458SSam Leffler result = ipsec_in_reject(sp, m); 147588768458SSam Leffler if (result) 1476603724d3SBjoern A. Zeeb V_ipsec4stat.ips_in_polvio++; 147788768458SSam Leffler KEY_FREESP(&sp); 147888768458SSam Leffler } else { 147988768458SSam Leffler result = 0; /* XXX should be panic ? 148088768458SSam Leffler * -> No, there may be error. */ 148188768458SSam Leffler } 148288768458SSam Leffler return result; 148388768458SSam Leffler } 148488768458SSam Leffler 148588768458SSam Leffler #ifdef INET6 148688768458SSam Leffler /* 148788768458SSam Leffler * Check AH/ESP integrity. 148888768458SSam Leffler * This function is called from tcp6_input(), udp6_input(), 148988768458SSam Leffler * and {ah,esp}6_input for tunnel mode 149088768458SSam Leffler */ 149188768458SSam Leffler int 149288768458SSam Leffler ipsec6_in_reject(m, inp) 149388768458SSam Leffler struct mbuf *m; 149488768458SSam Leffler struct inpcb *inp; 149588768458SSam Leffler { 149688768458SSam Leffler struct secpolicy *sp = NULL; 149788768458SSam Leffler int error; 149888768458SSam Leffler int result; 149988768458SSam Leffler 150088768458SSam Leffler /* sanity check */ 150188768458SSam Leffler if (m == NULL) 150288768458SSam Leffler return 0; /* XXX should be panic ? */ 150388768458SSam Leffler 150488768458SSam Leffler /* get SP for this packet. 150588768458SSam Leffler * When we are called from ip_forward(), we call 150688768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 150788768458SSam Leffler */ 150888768458SSam Leffler if (inp == NULL) 150988768458SSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); 151088768458SSam Leffler else 151188768458SSam Leffler sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); 151288768458SSam Leffler 151388768458SSam Leffler if (sp != NULL) { 151488768458SSam Leffler result = ipsec_in_reject(sp, m); 151588768458SSam Leffler if (result) 1516603724d3SBjoern A. Zeeb V_ipsec6stat.ips_in_polvio++; 151788768458SSam Leffler KEY_FREESP(&sp); 151888768458SSam Leffler } else { 151988768458SSam Leffler result = 0; 152088768458SSam Leffler } 152188768458SSam Leffler return result; 152288768458SSam Leffler } 152388768458SSam Leffler #endif 152488768458SSam Leffler 152588768458SSam Leffler /* 152688768458SSam Leffler * compute the byte size to be occupied by IPsec header. 152788768458SSam Leffler * in case it is tunneled, it includes the size of outer IP header. 152888768458SSam Leffler * NOTE: SP passed is free in this function. 152988768458SSam Leffler */ 153088768458SSam Leffler static size_t 153188768458SSam Leffler ipsec_hdrsiz(struct secpolicy *sp) 153288768458SSam Leffler { 153388768458SSam Leffler struct ipsecrequest *isr; 153488768458SSam Leffler size_t siz; 153588768458SSam Leffler 153688768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 15379ffa9677SSam Leffler printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); 153888768458SSam Leffler 153988768458SSam Leffler switch (sp->policy) { 154088768458SSam Leffler case IPSEC_POLICY_DISCARD: 154188768458SSam Leffler case IPSEC_POLICY_BYPASS: 154288768458SSam Leffler case IPSEC_POLICY_NONE: 154388768458SSam Leffler return 0; 154488768458SSam Leffler } 154588768458SSam Leffler 15469ffa9677SSam Leffler IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, 15479ffa9677SSam Leffler ("invalid policy %u", sp->policy)); 154888768458SSam Leffler 154988768458SSam Leffler siz = 0; 155088768458SSam Leffler for (isr = sp->req; isr != NULL; isr = isr->next) { 155188768458SSam Leffler size_t clen = 0; 155288768458SSam Leffler 155388768458SSam Leffler switch (isr->saidx.proto) { 155488768458SSam Leffler case IPPROTO_ESP: 155588768458SSam Leffler clen = esp_hdrsiz(isr->sav); 155688768458SSam Leffler break; 155788768458SSam Leffler case IPPROTO_AH: 155888768458SSam Leffler clen = ah_hdrsiz(isr->sav); 155988768458SSam Leffler break; 156088768458SSam Leffler case IPPROTO_IPCOMP: 156188768458SSam Leffler clen = sizeof(struct ipcomp); 156288768458SSam Leffler break; 156388768458SSam Leffler } 156488768458SSam Leffler 156588768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { 156688768458SSam Leffler switch (isr->saidx.dst.sa.sa_family) { 156788768458SSam Leffler case AF_INET: 156888768458SSam Leffler clen += sizeof(struct ip); 156988768458SSam Leffler break; 157088768458SSam Leffler #ifdef INET6 157188768458SSam Leffler case AF_INET6: 157288768458SSam Leffler clen += sizeof(struct ip6_hdr); 157388768458SSam Leffler break; 157488768458SSam Leffler #endif 157588768458SSam Leffler default: 15769ffa9677SSam Leffler ipseclog((LOG_ERR, "%s: unknown AF %d in " 15779ffa9677SSam Leffler "IPsec tunnel SA\n", __func__, 157888768458SSam Leffler ((struct sockaddr *)&isr->saidx.dst)->sa_family)); 157988768458SSam Leffler break; 158088768458SSam Leffler } 158188768458SSam Leffler } 158288768458SSam Leffler siz += clen; 158388768458SSam Leffler } 158488768458SSam Leffler 158588768458SSam Leffler return siz; 158688768458SSam Leffler } 158788768458SSam Leffler 158888768458SSam Leffler /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ 158988768458SSam Leffler size_t 159088768458SSam Leffler ipsec4_hdrsiz(m, dir, inp) 159188768458SSam Leffler struct mbuf *m; 159288768458SSam Leffler u_int dir; 159388768458SSam Leffler struct inpcb *inp; 159488768458SSam Leffler { 159588768458SSam Leffler struct secpolicy *sp; 159688768458SSam Leffler int error; 159788768458SSam Leffler size_t size; 159888768458SSam Leffler 15999ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 160088768458SSam Leffler 160188768458SSam Leffler /* get SP for this packet. 160288768458SSam Leffler * When we are called from ip_forward(), we call 160388768458SSam Leffler * ipsec_getpolicybyaddr() with IP_FORWARDING flag. 160488768458SSam Leffler */ 160588768458SSam Leffler if (inp == NULL) 160688768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 160788768458SSam Leffler else 160888768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, inp, &error); 160988768458SSam Leffler 161088768458SSam Leffler if (sp != NULL) { 161188768458SSam Leffler size = ipsec_hdrsiz(sp); 161288768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 16139ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, 161488768458SSam Leffler (unsigned long)size)); 161588768458SSam Leffler 161688768458SSam Leffler KEY_FREESP(&sp); 161788768458SSam Leffler } else { 16184a67e051SBjoern A. Zeeb size = 0; /* XXX should be panic ? 16194a67e051SBjoern A. Zeeb * -> No, we are called w/o knowing if 16204a67e051SBjoern A. Zeeb * IPsec processing is needed. */ 162188768458SSam Leffler } 162288768458SSam Leffler return size; 162388768458SSam Leffler } 162488768458SSam Leffler 162588768458SSam Leffler #ifdef INET6 162688768458SSam Leffler /* This function is called from ipsec6_hdrsize_tcp(), 162788768458SSam Leffler * and maybe from ip6_forward.() 162888768458SSam Leffler */ 162988768458SSam Leffler size_t 163088768458SSam Leffler ipsec6_hdrsiz(m, dir, in6p) 163188768458SSam Leffler struct mbuf *m; 163288768458SSam Leffler u_int dir; 163388768458SSam Leffler struct in6pcb *in6p; 163488768458SSam Leffler { 163588768458SSam Leffler struct secpolicy *sp; 163688768458SSam Leffler int error; 163788768458SSam Leffler size_t size; 163888768458SSam Leffler 16399ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 16409ffa9677SSam Leffler IPSEC_ASSERT(in6p == NULL || in6p->in6p_socket != NULL, 16419ffa9677SSam Leffler ("socket w/o inpcb")); 164288768458SSam Leffler 164388768458SSam Leffler /* get SP for this packet */ 164488768458SSam Leffler /* XXX Is it right to call with IP_FORWARDING. */ 164588768458SSam Leffler if (in6p == NULL) 164688768458SSam Leffler sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); 164788768458SSam Leffler else 164888768458SSam Leffler sp = ipsec_getpolicybysock(m, dir, in6p, &error); 164988768458SSam Leffler 165088768458SSam Leffler if (sp == NULL) 165188768458SSam Leffler return 0; 165288768458SSam Leffler size = ipsec_hdrsiz(sp); 165388768458SSam Leffler KEYDEBUG(KEYDEBUG_IPSEC_DATA, 16549ffa9677SSam Leffler printf("%s: size:%lu.\n", __func__, (unsigned long)size)); 165588768458SSam Leffler KEY_FREESP(&sp); 165688768458SSam Leffler 165788768458SSam Leffler return size; 165888768458SSam Leffler } 165988768458SSam Leffler #endif /*INET6*/ 166088768458SSam Leffler 166188768458SSam Leffler /* 166288768458SSam Leffler * Check the variable replay window. 166388768458SSam Leffler * ipsec_chkreplay() performs replay check before ICV verification. 166488768458SSam Leffler * ipsec_updatereplay() updates replay bitmap. This must be called after 166588768458SSam Leffler * ICV verification (it also performs replay check, which is usually done 166688768458SSam Leffler * beforehand). 166788768458SSam Leffler * 0 (zero) is returned if packet disallowed, 1 if packet permitted. 166888768458SSam Leffler * 166988768458SSam Leffler * based on RFC 2401. 167088768458SSam Leffler */ 167188768458SSam Leffler int 167288768458SSam Leffler ipsec_chkreplay(seq, sav) 167388768458SSam Leffler u_int32_t seq; 167488768458SSam Leffler struct secasvar *sav; 167588768458SSam Leffler { 167688768458SSam Leffler const struct secreplay *replay; 167788768458SSam Leffler u_int32_t diff; 167888768458SSam Leffler int fr; 167988768458SSam Leffler u_int32_t wsizeb; /* constant: bits of window size */ 168088768458SSam Leffler int frlast; /* constant: last frame */ 168188768458SSam Leffler 16829ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 16839ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 168488768458SSam Leffler 168588768458SSam Leffler replay = sav->replay; 168688768458SSam Leffler 168788768458SSam Leffler if (replay->wsize == 0) 168888768458SSam Leffler return 1; /* no need to check replay. */ 168988768458SSam Leffler 169088768458SSam Leffler /* constant */ 169188768458SSam Leffler frlast = replay->wsize - 1; 169288768458SSam Leffler wsizeb = replay->wsize << 3; 169388768458SSam Leffler 169488768458SSam Leffler /* sequence number of 0 is invalid */ 169588768458SSam Leffler if (seq == 0) 169688768458SSam Leffler return 0; 169788768458SSam Leffler 169888768458SSam Leffler /* first time is always okay */ 169988768458SSam Leffler if (replay->count == 0) 170088768458SSam Leffler return 1; 170188768458SSam Leffler 170288768458SSam Leffler if (seq > replay->lastseq) { 170388768458SSam Leffler /* larger sequences are okay */ 170488768458SSam Leffler return 1; 170588768458SSam Leffler } else { 170688768458SSam Leffler /* seq is equal or less than lastseq. */ 170788768458SSam Leffler diff = replay->lastseq - seq; 170888768458SSam Leffler 170988768458SSam Leffler /* over range to check, i.e. too old or wrapped */ 171088768458SSam Leffler if (diff >= wsizeb) 171188768458SSam Leffler return 0; 171288768458SSam Leffler 171388768458SSam Leffler fr = frlast - diff / 8; 171488768458SSam Leffler 171588768458SSam Leffler /* this packet already seen ? */ 171688768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 171788768458SSam Leffler return 0; 171888768458SSam Leffler 171988768458SSam Leffler /* out of order but good */ 172088768458SSam Leffler return 1; 172188768458SSam Leffler } 172288768458SSam Leffler } 172388768458SSam Leffler 172488768458SSam Leffler /* 172588768458SSam Leffler * check replay counter whether to update or not. 172688768458SSam Leffler * OUT: 0: OK 172788768458SSam Leffler * 1: NG 172888768458SSam Leffler */ 172988768458SSam Leffler int 173088768458SSam Leffler ipsec_updatereplay(seq, sav) 173188768458SSam Leffler u_int32_t seq; 173288768458SSam Leffler struct secasvar *sav; 173388768458SSam Leffler { 173488768458SSam Leffler struct secreplay *replay; 173588768458SSam Leffler u_int32_t diff; 173688768458SSam Leffler int fr; 173788768458SSam Leffler u_int32_t wsizeb; /* constant: bits of window size */ 173888768458SSam Leffler int frlast; /* constant: last frame */ 173988768458SSam Leffler 17409ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("Null SA")); 17419ffa9677SSam Leffler IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); 174288768458SSam Leffler 174388768458SSam Leffler replay = sav->replay; 174488768458SSam Leffler 174588768458SSam Leffler if (replay->wsize == 0) 174688768458SSam Leffler goto ok; /* no need to check replay. */ 174788768458SSam Leffler 174888768458SSam Leffler /* constant */ 174988768458SSam Leffler frlast = replay->wsize - 1; 175088768458SSam Leffler wsizeb = replay->wsize << 3; 175188768458SSam Leffler 175288768458SSam Leffler /* sequence number of 0 is invalid */ 175388768458SSam Leffler if (seq == 0) 175488768458SSam Leffler return 1; 175588768458SSam Leffler 175688768458SSam Leffler /* first time */ 175788768458SSam Leffler if (replay->count == 0) { 175888768458SSam Leffler replay->lastseq = seq; 175988768458SSam Leffler bzero(replay->bitmap, replay->wsize); 176088768458SSam Leffler (replay->bitmap)[frlast] = 1; 176188768458SSam Leffler goto ok; 176288768458SSam Leffler } 176388768458SSam Leffler 176488768458SSam Leffler if (seq > replay->lastseq) { 176588768458SSam Leffler /* seq is larger than lastseq. */ 176688768458SSam Leffler diff = seq - replay->lastseq; 176788768458SSam Leffler 176888768458SSam Leffler /* new larger sequence number */ 176988768458SSam Leffler if (diff < wsizeb) { 177088768458SSam Leffler /* In window */ 177188768458SSam Leffler /* set bit for this packet */ 177288768458SSam Leffler vshiftl(replay->bitmap, diff, replay->wsize); 177388768458SSam Leffler (replay->bitmap)[frlast] |= 1; 177488768458SSam Leffler } else { 177588768458SSam Leffler /* this packet has a "way larger" */ 177688768458SSam Leffler bzero(replay->bitmap, replay->wsize); 177788768458SSam Leffler (replay->bitmap)[frlast] = 1; 177888768458SSam Leffler } 177988768458SSam Leffler replay->lastseq = seq; 178088768458SSam Leffler 178188768458SSam Leffler /* larger is good */ 178288768458SSam Leffler } else { 178388768458SSam Leffler /* seq is equal or less than lastseq. */ 178488768458SSam Leffler diff = replay->lastseq - seq; 178588768458SSam Leffler 178688768458SSam Leffler /* over range to check, i.e. too old or wrapped */ 178788768458SSam Leffler if (diff >= wsizeb) 178888768458SSam Leffler return 1; 178988768458SSam Leffler 179088768458SSam Leffler fr = frlast - diff / 8; 179188768458SSam Leffler 179288768458SSam Leffler /* this packet already seen ? */ 179388768458SSam Leffler if ((replay->bitmap)[fr] & (1 << (diff % 8))) 179488768458SSam Leffler return 1; 179588768458SSam Leffler 179688768458SSam Leffler /* mark as seen */ 179788768458SSam Leffler (replay->bitmap)[fr] |= (1 << (diff % 8)); 179888768458SSam Leffler 179988768458SSam Leffler /* out of order but good */ 180088768458SSam Leffler } 180188768458SSam Leffler 180288768458SSam Leffler ok: 180388768458SSam Leffler if (replay->count == ~0) { 180488768458SSam Leffler 180588768458SSam Leffler /* set overflow flag */ 180688768458SSam Leffler replay->overflow++; 180788768458SSam Leffler 180888768458SSam Leffler /* don't increment, no more packets accepted */ 180988768458SSam Leffler if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) 181088768458SSam Leffler return 1; 181188768458SSam Leffler 18129ffa9677SSam Leffler ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", 18139ffa9677SSam Leffler __func__, replay->overflow, ipsec_logsastr(sav))); 181488768458SSam Leffler } 181588768458SSam Leffler 181688768458SSam Leffler replay->count++; 181788768458SSam Leffler 181888768458SSam Leffler return 0; 181988768458SSam Leffler } 182088768458SSam Leffler 182188768458SSam Leffler /* 1822d24ff94bSHiten Pandya * shift variable length buffer to left. 182388768458SSam Leffler * IN: bitmap: pointer to the buffer 182488768458SSam Leffler * nbit: the number of to shift. 182588768458SSam Leffler * wsize: buffer size (bytes). 182688768458SSam Leffler */ 182788768458SSam Leffler static void 182888768458SSam Leffler vshiftl(bitmap, nbit, wsize) 182988768458SSam Leffler unsigned char *bitmap; 183088768458SSam Leffler int nbit, wsize; 183188768458SSam Leffler { 183288768458SSam Leffler int s, j, i; 183388768458SSam Leffler unsigned char over; 183488768458SSam Leffler 183588768458SSam Leffler for (j = 0; j < nbit; j += 8) { 183688768458SSam Leffler s = (nbit - j < 8) ? (nbit - j): 8; 183788768458SSam Leffler bitmap[0] <<= s; 183888768458SSam Leffler for (i = 1; i < wsize; i++) { 183988768458SSam Leffler over = (bitmap[i] >> (8 - s)); 184088768458SSam Leffler bitmap[i] <<= s; 184188768458SSam Leffler bitmap[i-1] |= over; 184288768458SSam Leffler } 184388768458SSam Leffler } 184488768458SSam Leffler 184588768458SSam Leffler return; 184688768458SSam Leffler } 184788768458SSam Leffler 184888768458SSam Leffler /* Return a printable string for the IPv4 address. */ 184988768458SSam Leffler static char * 185088768458SSam Leffler inet_ntoa4(struct in_addr ina) 185188768458SSam Leffler { 185288768458SSam Leffler static char buf[4][4 * sizeof "123" + 4]; 185388768458SSam Leffler unsigned char *ucp = (unsigned char *) &ina; 185488768458SSam Leffler static int i = 3; 185588768458SSam Leffler 18561d54aa3bSBjoern A. Zeeb /* XXX-BZ returns static buffer. */ 185788768458SSam Leffler i = (i + 1) % 4; 185888768458SSam Leffler sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, 185988768458SSam Leffler ucp[2] & 0xff, ucp[3] & 0xff); 186088768458SSam Leffler return (buf[i]); 186188768458SSam Leffler } 186288768458SSam Leffler 186388768458SSam Leffler /* Return a printable string for the address. */ 186488768458SSam Leffler char * 186588768458SSam Leffler ipsec_address(union sockaddr_union* sa) 186688768458SSam Leffler { 1867224c45c4SBjoern A. Zeeb #ifdef INET6 18681d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 18691d54aa3bSBjoern A. Zeeb #endif 187088768458SSam Leffler switch (sa->sa.sa_family) { 187149ddabdfSPawel Jakub Dawidek #ifdef INET 187288768458SSam Leffler case AF_INET: 187388768458SSam Leffler return inet_ntoa4(sa->sin.sin_addr); 187488768458SSam Leffler #endif /* INET */ 187588768458SSam Leffler 187649ddabdfSPawel Jakub Dawidek #ifdef INET6 187788768458SSam Leffler case AF_INET6: 18781d54aa3bSBjoern A. Zeeb return ip6_sprintf(ip6buf, &sa->sin6.sin6_addr); 187988768458SSam Leffler #endif /* INET6 */ 188088768458SSam Leffler 188188768458SSam Leffler default: 188288768458SSam Leffler return "(unknown address family)"; 188388768458SSam Leffler } 188488768458SSam Leffler } 188588768458SSam Leffler 188688768458SSam Leffler const char * 188788768458SSam Leffler ipsec_logsastr(sav) 188888768458SSam Leffler struct secasvar *sav; 188988768458SSam Leffler { 189088768458SSam Leffler static char buf[256]; 189188768458SSam Leffler char *p; 189288768458SSam Leffler struct secasindex *saidx = &sav->sah->saidx; 189388768458SSam Leffler 18949ffa9677SSam Leffler IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, 18959ffa9677SSam Leffler ("address family mismatch")); 189688768458SSam Leffler 189788768458SSam Leffler p = buf; 189888768458SSam Leffler snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); 189988768458SSam Leffler while (p && *p) 190088768458SSam Leffler p++; 190188768458SSam Leffler /* NB: only use ipsec_address on one address at a time */ 190288768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "src=%s ", 190388768458SSam Leffler ipsec_address(&saidx->src)); 190488768458SSam Leffler while (p && *p) 190588768458SSam Leffler p++; 190688768458SSam Leffler snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", 190788768458SSam Leffler ipsec_address(&saidx->dst)); 190888768458SSam Leffler 190988768458SSam Leffler return buf; 191088768458SSam Leffler } 191188768458SSam Leffler 191288768458SSam Leffler void 191388768458SSam Leffler ipsec_dumpmbuf(m) 191488768458SSam Leffler struct mbuf *m; 191588768458SSam Leffler { 191688768458SSam Leffler int totlen; 191788768458SSam Leffler int i; 191888768458SSam Leffler u_char *p; 191988768458SSam Leffler 192088768458SSam Leffler totlen = 0; 192188768458SSam Leffler printf("---\n"); 192288768458SSam Leffler while (m) { 192388768458SSam Leffler p = mtod(m, u_char *); 192488768458SSam Leffler for (i = 0; i < m->m_len; i++) { 192588768458SSam Leffler printf("%02x ", p[i]); 192688768458SSam Leffler totlen++; 192788768458SSam Leffler if (totlen % 16 == 0) 192888768458SSam Leffler printf("\n"); 192988768458SSam Leffler } 193088768458SSam Leffler m = m->m_next; 193188768458SSam Leffler } 193288768458SSam Leffler if (totlen % 16 != 0) 193388768458SSam Leffler printf("\n"); 193488768458SSam Leffler printf("---\n"); 193588768458SSam Leffler } 193688768458SSam Leffler 19378381996eSSam Leffler static void 19388381996eSSam Leffler ipsec_attach(void) 19398381996eSSam Leffler { 1940603724d3SBjoern A. Zeeb SECPOLICY_LOCK_INIT(&V_ip4_def_policy); 19418381996eSSam Leffler ip4_def_policy.refcnt = 1; /* NB: disallow free */ 19428381996eSSam Leffler } 1943237fdd78SRobert Watson SYSINIT(ipsec, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, ipsec_attach, NULL); 19448381996eSSam Leffler 19458381996eSSam Leffler 194688768458SSam Leffler /* XXX this stuff doesn't belong here... */ 194788768458SSam Leffler 194888768458SSam Leffler static struct xformsw* xforms = NULL; 194988768458SSam Leffler 195088768458SSam Leffler /* 195188768458SSam Leffler * Register a transform; typically at system startup. 195288768458SSam Leffler */ 195388768458SSam Leffler void 195488768458SSam Leffler xform_register(struct xformsw* xsp) 195588768458SSam Leffler { 195688768458SSam Leffler xsp->xf_next = xforms; 195788768458SSam Leffler xforms = xsp; 195888768458SSam Leffler } 195988768458SSam Leffler 196088768458SSam Leffler /* 196188768458SSam Leffler * Initialize transform support in an sav. 196288768458SSam Leffler */ 196388768458SSam Leffler int 196488768458SSam Leffler xform_init(struct secasvar *sav, int xftype) 196588768458SSam Leffler { 196688768458SSam Leffler struct xformsw *xsp; 196788768458SSam Leffler 196882a6d6acSSam Leffler if (sav->tdb_xform != NULL) /* previously initialized */ 196982a6d6acSSam Leffler return 0; 197088768458SSam Leffler for (xsp = xforms; xsp; xsp = xsp->xf_next) 197188768458SSam Leffler if (xsp->xf_type == xftype) 197288768458SSam Leffler return (*xsp->xf_init)(sav, xsp); 197388768458SSam Leffler return EINVAL; 197488768458SSam Leffler } 1975