188768458SSam Leffler /* $FreeBSD$ */ 288768458SSam Leffler /* $KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $ */ 388768458SSam Leffler 4c398230bSWarner Losh /*- 551369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 651369649SPedro F. Giffuni * 788768458SSam Leffler * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 888768458SSam Leffler * All rights reserved. 988768458SSam Leffler * 1088768458SSam Leffler * Redistribution and use in source and binary forms, with or without 1188768458SSam Leffler * modification, are permitted provided that the following conditions 1288768458SSam Leffler * are met: 1388768458SSam Leffler * 1. Redistributions of source code must retain the above copyright 1488768458SSam Leffler * notice, this list of conditions and the following disclaimer. 1588768458SSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 1688768458SSam Leffler * notice, this list of conditions and the following disclaimer in the 1788768458SSam Leffler * documentation and/or other materials provided with the distribution. 1888768458SSam Leffler * 3. Neither the name of the project nor the names of its contributors 1988768458SSam Leffler * may be used to endorse or promote products derived from this software 2088768458SSam Leffler * without specific prior written permission. 2188768458SSam Leffler * 2288768458SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2388768458SSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2488768458SSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2588768458SSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2688768458SSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2788768458SSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2888768458SSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2988768458SSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3088768458SSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3188768458SSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3288768458SSam Leffler * SUCH DAMAGE. 3388768458SSam Leffler */ 3488768458SSam Leffler 3588768458SSam Leffler #include "opt_ipsec.h" 3688768458SSam Leffler 3788768458SSam Leffler /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */ 3888768458SSam Leffler 3988768458SSam Leffler #include <sys/types.h> 4088768458SSam Leffler #include <sys/param.h> 4188768458SSam Leffler #include <sys/domain.h> 4288768458SSam Leffler #include <sys/errno.h> 4388768458SSam Leffler #include <sys/kernel.h> 448eafa045SBruce M Simpson #include <sys/lock.h> 4588768458SSam Leffler #include <sys/malloc.h> 4688768458SSam Leffler #include <sys/mbuf.h> 478eafa045SBruce M Simpson #include <sys/mutex.h> 48190320e2SBjoern A. Zeeb #include <sys/priv.h> 4988768458SSam Leffler #include <sys/protosw.h> 5088768458SSam Leffler #include <sys/signalvar.h> 5188768458SSam Leffler #include <sys/socket.h> 5288768458SSam Leffler #include <sys/socketvar.h> 5388768458SSam Leffler #include <sys/sysctl.h> 5488768458SSam Leffler #include <sys/systm.h> 5588768458SSam Leffler 568b615593SMarko Zec #include <net/if.h> 57eedc7fd9SGleb Smirnoff #include <net/vnet.h> 5888768458SSam Leffler 598b615593SMarko Zec #include <netinet/in.h> 608b615593SMarko Zec 6188768458SSam Leffler #include <net/pfkeyv2.h> 6288768458SSam Leffler #include <netipsec/key.h> 6388768458SSam Leffler #include <netipsec/keysock.h> 6488768458SSam Leffler #include <netipsec/key_debug.h> 658b615593SMarko Zec #include <netipsec/ipsec.h> 6688768458SSam Leffler 6788768458SSam Leffler #include <machine/stdarg.h> 6888768458SSam Leffler 69*ea7be129SGleb Smirnoff static struct mtx keysock_mtx; 70*ea7be129SGleb Smirnoff MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF); 71*ea7be129SGleb Smirnoff 72*ea7be129SGleb Smirnoff #define KEYSOCK_LOCK() mtx_lock(&keysock_mtx) 73*ea7be129SGleb Smirnoff #define KEYSOCK_UNLOCK() mtx_unlock(&keysock_mtx) 74*ea7be129SGleb Smirnoff 75*ea7be129SGleb Smirnoff VNET_DEFINE_STATIC(LIST_HEAD(, keycb), keycb_list); 76*ea7be129SGleb Smirnoff #define V_keycb_list VNET(keycb_list) 7788768458SSam Leffler 78eddfbb76SRobert Watson static struct sockaddr key_src = { 2, PF_KEY, }; 7988768458SSam Leffler 80*ea7be129SGleb Smirnoff static int key_sendup0(struct keycb *, struct mbuf *, int); 8188768458SSam Leffler 82db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct pfkeystat, pfkeystat); 83db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(pfkeystat); 84db8c0879SAndrey V. Elsukov 85db8c0879SAndrey V. Elsukov #ifdef VIMAGE 86db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(pfkeystat); 87db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 88eddfbb76SRobert Watson 89*ea7be129SGleb Smirnoff static int 90*ea7be129SGleb Smirnoff key_send(struct socket *so, int flags, struct mbuf *m, 91*ea7be129SGleb Smirnoff struct sockaddr *nam, struct mbuf *control, struct thread *td) 9288768458SSam Leffler { 9388768458SSam Leffler struct sadb_msg *msg; 9488768458SSam Leffler int len, error = 0; 9588768458SSam Leffler 96*ea7be129SGleb Smirnoff if ((flags & PRUS_OOB) || control != NULL) { 97*ea7be129SGleb Smirnoff m_freem(m); 98*ea7be129SGleb Smirnoff if (control != NULL) 99*ea7be129SGleb Smirnoff m_freem(control); 100*ea7be129SGleb Smirnoff return (EOPNOTSUPP); 101*ea7be129SGleb Smirnoff } 10288768458SSam Leffler 103a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(out_total); 104a04d64d8SAndrey V. Elsukov PFKEYSTAT_ADD(out_bytes, m->m_pkthdr.len); 10588768458SSam Leffler 10688768458SSam Leffler len = m->m_pkthdr.len; 10788768458SSam Leffler if (len < sizeof(struct sadb_msg)) { 108a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(out_tooshort); 10988768458SSam Leffler error = EINVAL; 11088768458SSam Leffler goto end; 11188768458SSam Leffler } 11288768458SSam Leffler 11388768458SSam Leffler if (m->m_len < sizeof(struct sadb_msg)) { 114155d72c4SPedro F. Giffuni if ((m = m_pullup(m, sizeof(struct sadb_msg))) == NULL) { 115a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(out_nomem); 11688768458SSam Leffler error = ENOBUFS; 11788768458SSam Leffler goto end; 11888768458SSam Leffler } 11988768458SSam Leffler } 12088768458SSam Leffler 121fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 12288768458SSam Leffler 123fcf59617SAndrey V. Elsukov KEYDBG(KEY_DUMP, kdebug_mbuf(m)); 12488768458SSam Leffler 12588768458SSam Leffler msg = mtod(m, struct sadb_msg *); 126a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(out_msgtype[msg->sadb_msg_type]); 12788768458SSam Leffler if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) { 128a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(out_invlen); 12988768458SSam Leffler error = EINVAL; 13088768458SSam Leffler goto end; 13188768458SSam Leffler } 13288768458SSam Leffler 13388768458SSam Leffler error = key_parse(m, so); 13488768458SSam Leffler m = NULL; 13588768458SSam Leffler end: 13688768458SSam Leffler if (m) 13788768458SSam Leffler m_freem(m); 13888768458SSam Leffler return error; 13988768458SSam Leffler } 14088768458SSam Leffler 14188768458SSam Leffler /* 14288768458SSam Leffler * send message to the socket. 14388768458SSam Leffler */ 14488768458SSam Leffler static int 145*ea7be129SGleb Smirnoff key_sendup0(struct keycb *kp, struct mbuf *m, int promisc) 14688768458SSam Leffler { 14788768458SSam Leffler 14888768458SSam Leffler if (promisc) { 14988768458SSam Leffler struct sadb_msg *pmsg; 15088768458SSam Leffler 151eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT); 1523d6aff56SAndrey V. Elsukov if (m == NULL) { 153a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_nomem); 1543d6aff56SAndrey V. Elsukov return (ENOBUFS); 15588768458SSam Leffler } 15688768458SSam Leffler pmsg = mtod(m, struct sadb_msg *); 15788768458SSam Leffler bzero(pmsg, sizeof(*pmsg)); 15888768458SSam Leffler pmsg->sadb_msg_version = PF_KEY_V2; 15988768458SSam Leffler pmsg->sadb_msg_type = SADB_X_PROMISC; 16088768458SSam Leffler pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); 16188768458SSam Leffler /* pid and seq? */ 16288768458SSam Leffler 163a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_msgtype[pmsg->sadb_msg_type]); 16488768458SSam Leffler } 16588768458SSam Leffler 166*ea7be129SGleb Smirnoff if (!sbappendaddr(&kp->kp_socket->so_rcv, &key_src, m, NULL)) { 167a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_nomem); 16888768458SSam Leffler m_freem(m); 169*ea7be129SGleb Smirnoff soroverflow(kp->kp_socket); 1707045b160SRoy Marples return ENOBUFS; 1717045b160SRoy Marples } 1727045b160SRoy Marples 173*ea7be129SGleb Smirnoff sorwakeup(kp->kp_socket); 1747045b160SRoy Marples return 0; 17588768458SSam Leffler } 17688768458SSam Leffler 17788768458SSam Leffler /* so can be NULL if target != KEY_SENDUP_ONE */ 17888768458SSam Leffler int 1792e84e6eaSAndrey V. Elsukov key_sendup_mbuf(struct socket *so, struct mbuf *m, int target) 18088768458SSam Leffler { 18188768458SSam Leffler struct mbuf *n; 18288768458SSam Leffler struct keycb *kp; 18388768458SSam Leffler int error = 0; 18488768458SSam Leffler 185e3004d24SAndrey V. Elsukov KASSERT(m != NULL, ("NULL mbuf pointer was passed.")); 186e3004d24SAndrey V. Elsukov KASSERT(so != NULL || target != KEY_SENDUP_ONE, 187e3004d24SAndrey V. Elsukov ("NULL socket pointer was passed.")); 188d158b221SAndrey V. Elsukov KASSERT(target == KEY_SENDUP_ONE || target == KEY_SENDUP_ALL || 189d158b221SAndrey V. Elsukov target == KEY_SENDUP_REGISTERED, ("Wrong target %d", target)); 19088768458SSam Leffler 191a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_total); 192a04d64d8SAndrey V. Elsukov PFKEYSTAT_ADD(in_bytes, m->m_pkthdr.len); 19388768458SSam Leffler if (m->m_len < sizeof(struct sadb_msg)) { 19488768458SSam Leffler m = m_pullup(m, sizeof(struct sadb_msg)); 19588768458SSam Leffler if (m == NULL) { 196a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_nomem); 19788768458SSam Leffler return ENOBUFS; 19888768458SSam Leffler } 19988768458SSam Leffler } 20088768458SSam Leffler if (m->m_len >= sizeof(struct sadb_msg)) { 20188768458SSam Leffler struct sadb_msg *msg; 20288768458SSam Leffler msg = mtod(m, struct sadb_msg *); 203a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_msgtype[msg->sadb_msg_type]); 20488768458SSam Leffler } 205*ea7be129SGleb Smirnoff KEYSOCK_LOCK(); 206*ea7be129SGleb Smirnoff LIST_FOREACH(kp, &V_keycb_list, kp_next) { 20788768458SSam Leffler /* 20888768458SSam Leffler * If you are in promiscuous mode, and when you get broadcasted 20988768458SSam Leffler * reply, you'll get two PF_KEY messages. 21088768458SSam Leffler * (based on pf_key@inner.net message on 14 Oct 1998) 21188768458SSam Leffler */ 212017a5e58SAndrey V. Elsukov if (kp->kp_promisc) { 213017a5e58SAndrey V. Elsukov n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 214017a5e58SAndrey V. Elsukov if (n != NULL) 215*ea7be129SGleb Smirnoff key_sendup0(kp, n, 1); 216017a5e58SAndrey V. Elsukov else 217017a5e58SAndrey V. Elsukov PFKEYSTAT_INC(in_nomem); 21888768458SSam Leffler } 21988768458SSam Leffler 22088768458SSam Leffler /* the exact target will be processed later */ 221*ea7be129SGleb Smirnoff if (so != NULL && so->so_pcb == kp) 22288768458SSam Leffler continue; 22388768458SSam Leffler 224017a5e58SAndrey V. Elsukov if (target == KEY_SENDUP_ONE || ( 225017a5e58SAndrey V. Elsukov target == KEY_SENDUP_REGISTERED && kp->kp_registered == 0)) 22688768458SSam Leffler continue; 22788768458SSam Leffler 228017a5e58SAndrey V. Elsukov /* KEY_SENDUP_ALL + KEY_SENDUP_REGISTERED */ 229017a5e58SAndrey V. Elsukov n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 230017a5e58SAndrey V. Elsukov if (n == NULL) { 231a04d64d8SAndrey V. Elsukov PFKEYSTAT_INC(in_nomem); 232017a5e58SAndrey V. Elsukov /* Try send to another socket */ 233017a5e58SAndrey V. Elsukov continue; 23488768458SSam Leffler } 23588768458SSam Leffler 236*ea7be129SGleb Smirnoff if (key_sendup0(kp, n, 0) == 0) 237017a5e58SAndrey V. Elsukov PFKEYSTAT_INC(in_msgtarget[target]); 23888768458SSam Leffler } 23988768458SSam Leffler 240017a5e58SAndrey V. Elsukov if (so) { /* KEY_SENDUP_ONE */ 241*ea7be129SGleb Smirnoff error = key_sendup0(so->so_pcb, m, 0); 242017a5e58SAndrey V. Elsukov if (error == 0) 243017a5e58SAndrey V. Elsukov PFKEYSTAT_INC(in_msgtarget[KEY_SENDUP_ONE]); 24488768458SSam Leffler } else { 24588768458SSam Leffler error = 0; 24688768458SSam Leffler m_freem(m); 24788768458SSam Leffler } 248*ea7be129SGleb Smirnoff KEYSOCK_UNLOCK(); 249017a5e58SAndrey V. Elsukov return (error); 25088768458SSam Leffler } 25188768458SSam Leffler 252*ea7be129SGleb Smirnoff static u_long key_sendspace = 8192; 253*ea7be129SGleb Smirnoff SYSCTL_ULONG(_net_key, OID_AUTO, sendspace, CTLFLAG_RW, &key_sendspace, 0, 254*ea7be129SGleb Smirnoff "Default key socket send space"); 255*ea7be129SGleb Smirnoff static u_long key_recvspace = 8192; 256*ea7be129SGleb Smirnoff SYSCTL_ULONG(_net_key, OID_AUTO, recvspace, CTLFLAG_RW, &key_recvspace, 0, 257*ea7be129SGleb Smirnoff "Default key socket receive space"); 25888768458SSam Leffler 25988768458SSam Leffler static int 26088768458SSam Leffler key_attach(struct socket *so, int proto, struct thread *td) 26188768458SSam Leffler { 26288768458SSam Leffler struct keycb *kp; 2632cb64cb2SGeorge V. Neville-Neil int error; 26488768458SSam Leffler 2652cb64cb2SGeorge V. Neville-Neil KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL")); 2662cb64cb2SGeorge V. Neville-Neil 267cf94a6a9SBjoern A. Zeeb if (td != NULL) { 268cf94a6a9SBjoern A. Zeeb error = priv_check(td, PRIV_NET_RAW); 269cf94a6a9SBjoern A. Zeeb if (error) 270cf94a6a9SBjoern A. Zeeb return error; 271cf94a6a9SBjoern A. Zeeb } 272cf94a6a9SBjoern A. Zeeb 273*ea7be129SGleb Smirnoff error = soreserve(so, key_sendspace, key_recvspace); 274*ea7be129SGleb Smirnoff if (error) 275*ea7be129SGleb Smirnoff return (error); 27688768458SSam Leffler 277*ea7be129SGleb Smirnoff kp = malloc(sizeof(*kp), M_PCB, M_WAITOK); 278*ea7be129SGleb Smirnoff kp->kp_socket = so; 27988768458SSam Leffler kp->kp_promisc = kp->kp_registered = 0; 28088768458SSam Leffler 281*ea7be129SGleb Smirnoff so->so_pcb = kp; 28288768458SSam Leffler so->so_options |= SO_USELOOPBACK; 28388768458SSam Leffler 284*ea7be129SGleb Smirnoff KEYSOCK_LOCK(); 285*ea7be129SGleb Smirnoff LIST_INSERT_HEAD(&V_keycb_list, kp, kp_next); 286*ea7be129SGleb Smirnoff KEYSOCK_UNLOCK(); 287*ea7be129SGleb Smirnoff soisconnected(so); 288*ea7be129SGleb Smirnoff 289*ea7be129SGleb Smirnoff return (0); 29088768458SSam Leffler } 29188768458SSam Leffler 292a152f8a3SRobert Watson static void 29387b4dfd5SGeorge V. Neville-Neil key_close(struct socket *so) 294a152f8a3SRobert Watson { 295a152f8a3SRobert Watson 296*ea7be129SGleb Smirnoff soisdisconnected(so); 297a152f8a3SRobert Watson } 298a152f8a3SRobert Watson 299bc725eafSRobert Watson static void 30088768458SSam Leffler key_detach(struct socket *so) 30188768458SSam Leffler { 302*ea7be129SGleb Smirnoff struct keycb *kp = so->so_pcb; 30388768458SSam Leffler 30488768458SSam Leffler key_freereg(so); 305*ea7be129SGleb Smirnoff KEYSOCK_LOCK(); 306*ea7be129SGleb Smirnoff LIST_REMOVE(kp, kp_next); 307*ea7be129SGleb Smirnoff KEYSOCK_UNLOCK(); 308*ea7be129SGleb Smirnoff free(kp, M_PCB); 309*ea7be129SGleb Smirnoff so->so_pcb = NULL; 31088768458SSam Leffler } 31188768458SSam Leffler 31288768458SSam Leffler static int 31388768458SSam Leffler key_shutdown(struct socket *so) 31488768458SSam Leffler { 31588768458SSam Leffler 316*ea7be129SGleb Smirnoff socantsendmore(so); 317*ea7be129SGleb Smirnoff return (0); 31888768458SSam Leffler } 31988768458SSam Leffler 32088768458SSam Leffler struct pr_usrreqs key_usrreqs = { 321*ea7be129SGleb Smirnoff .pru_abort = key_close, 322756d52a1SPoul-Henning Kamp .pru_attach = key_attach, 323756d52a1SPoul-Henning Kamp .pru_detach = key_detach, 324756d52a1SPoul-Henning Kamp .pru_send = key_send, 325756d52a1SPoul-Henning Kamp .pru_shutdown = key_shutdown, 326a152f8a3SRobert Watson .pru_close = key_close, 32788768458SSam Leffler }; 32888768458SSam Leffler 32988768458SSam Leffler /* sysctl */ 3307029da5cSPawel Biernacki SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 3317029da5cSPawel Biernacki "Key Family"); 33288768458SSam Leffler 33388768458SSam Leffler /* 33488768458SSam Leffler * Definitions of protocols supported in the KEY domain. 33588768458SSam Leffler */ 33688768458SSam Leffler 33788768458SSam Leffler extern struct domain keydomain; 33888768458SSam Leffler 33988768458SSam Leffler struct protosw keysw[] = { 340303989a2SRuslan Ermilov { 341303989a2SRuslan Ermilov .pr_type = SOCK_RAW, 342303989a2SRuslan Ermilov .pr_domain = &keydomain, 343303989a2SRuslan Ermilov .pr_protocol = PF_KEY_V2, 344303989a2SRuslan Ermilov .pr_flags = PR_ATOMIC|PR_ADDR, 345303989a2SRuslan Ermilov .pr_usrreqs = &key_usrreqs 34688768458SSam Leffler } 34788768458SSam Leffler }; 34888768458SSam Leffler 349303989a2SRuslan Ermilov struct domain keydomain = { 350303989a2SRuslan Ermilov .dom_family = PF_KEY, 351303989a2SRuslan Ermilov .dom_name = "key", 352303989a2SRuslan Ermilov .dom_protosw = keysw, 35302abd400SPedro F. Giffuni .dom_protoswNPROTOSW = &keysw[nitems(keysw)] 354303989a2SRuslan Ermilov }; 3559880323aSGleb Smirnoff DOMAIN_SET(key); 356