xref: /freebsd/sys/netipsec/keysock.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /*	$KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "opt_ipsec.h"
35 
36 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/domain.h>
41 #include <sys/errno.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/mutex.h>
47 #include <sys/priv.h>
48 #include <sys/protosw.h>
49 #include <sys/signalvar.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/sysctl.h>
53 #include <sys/systm.h>
54 
55 #include <net/if.h>
56 #include <net/vnet.h>
57 
58 #include <netinet/in.h>
59 
60 #include <net/pfkeyv2.h>
61 #include <netipsec/key.h>
62 #include <netipsec/keysock.h>
63 #include <netipsec/key_debug.h>
64 #include <netipsec/ipsec.h>
65 
66 #include <machine/stdarg.h>
67 
68 static struct mtx keysock_mtx;
69 MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF);
70 
71 #define	KEYSOCK_LOCK()		mtx_lock(&keysock_mtx)
72 #define	KEYSOCK_UNLOCK()	mtx_unlock(&keysock_mtx)
73 
74 VNET_DEFINE_STATIC(LIST_HEAD(, keycb), keycb_list) =
75     LIST_HEAD_INITIALIZER(keycb_list);
76 #define	V_keycb_list		VNET(keycb_list)
77 
78 static struct sockaddr key_src = { 2, PF_KEY, };
79 
80 static int key_sendup0(struct keycb *, struct mbuf *, int);
81 
82 VNET_PCPUSTAT_DEFINE(struct pfkeystat, pfkeystat);
83 VNET_PCPUSTAT_SYSINIT(pfkeystat);
84 
85 #ifdef VIMAGE
86 VNET_PCPUSTAT_SYSUNINIT(pfkeystat);
87 #endif /* VIMAGE */
88 
89 static int
90 key_send(struct socket *so, int flags, struct mbuf *m,
91     struct sockaddr *nam, struct mbuf *control, struct thread *td)
92 {
93 	struct sadb_msg *msg;
94 	int len, error = 0;
95 
96 	if ((flags & PRUS_OOB) || control != NULL) {
97 		m_freem(m);
98 		if (control != NULL)
99 			m_freem(control);
100 		return (EOPNOTSUPP);
101 	}
102 
103 	PFKEYSTAT_INC(out_total);
104 	PFKEYSTAT_ADD(out_bytes, m->m_pkthdr.len);
105 
106 	len = m->m_pkthdr.len;
107 	if (len < sizeof(struct sadb_msg)) {
108 		PFKEYSTAT_INC(out_tooshort);
109 		error = EINVAL;
110 		goto end;
111 	}
112 
113 	if (m->m_len < sizeof(struct sadb_msg)) {
114 		if ((m = m_pullup(m, sizeof(struct sadb_msg))) == NULL) {
115 			PFKEYSTAT_INC(out_nomem);
116 			error = ENOBUFS;
117 			goto end;
118 		}
119 	}
120 
121 	M_ASSERTPKTHDR(m);
122 
123 	KEYDBG(KEY_DUMP, kdebug_mbuf(m));
124 
125 	msg = mtod(m, struct sadb_msg *);
126 	PFKEYSTAT_INC(out_msgtype[msg->sadb_msg_type]);
127 	if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
128 		PFKEYSTAT_INC(out_invlen);
129 		error = EINVAL;
130 		goto end;
131 	}
132 
133 	error = key_parse(m, so);
134 	m = NULL;
135 end:
136 	if (m != NULL)
137 		m_freem(m);
138 	return (error);
139 }
140 
141 /*
142  * send message to the socket.
143  */
144 static int
145 key_sendup0(struct keycb *kp, struct mbuf *m, int promisc)
146 {
147 
148 	if (promisc) {
149 		struct sadb_msg *pmsg;
150 
151 		M_PREPEND(m, sizeof(struct sadb_msg), M_NOWAIT);
152 		if (m == NULL) {
153 			PFKEYSTAT_INC(in_nomem);
154 			return (ENOBUFS);
155 		}
156 		pmsg = mtod(m, struct sadb_msg *);
157 		bzero(pmsg, sizeof(*pmsg));
158 		pmsg->sadb_msg_version = PF_KEY_V2;
159 		pmsg->sadb_msg_type = SADB_X_PROMISC;
160 		pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
161 		/* pid and seq? */
162 
163 		PFKEYSTAT_INC(in_msgtype[pmsg->sadb_msg_type]);
164 	}
165 
166 	if (!sbappendaddr(&kp->kp_socket->so_rcv, &key_src, m, NULL)) {
167 		PFKEYSTAT_INC(in_nomem);
168 		m_freem(m);
169 		soroverflow(kp->kp_socket);
170 		return (ENOBUFS);
171 	}
172 
173 	sorwakeup(kp->kp_socket);
174 	return (0);
175 }
176 
177 /* so can be NULL if target != KEY_SENDUP_ONE */
178 int
179 key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
180 {
181 	struct mbuf *n;
182 	struct keycb *kp;
183 	int error = 0;
184 
185 	KASSERT(m != NULL, ("NULL mbuf pointer was passed."));
186 	KASSERT(so != NULL || target != KEY_SENDUP_ONE,
187 	    ("NULL socket pointer was passed."));
188 	KASSERT(target == KEY_SENDUP_ONE || target == KEY_SENDUP_ALL ||
189 	    target == KEY_SENDUP_REGISTERED, ("Wrong target %d", target));
190 
191 	PFKEYSTAT_INC(in_total);
192 	PFKEYSTAT_ADD(in_bytes, m->m_pkthdr.len);
193 	if (m->m_len < sizeof(struct sadb_msg)) {
194 		m = m_pullup(m, sizeof(struct sadb_msg));
195 		if (m == NULL) {
196 			PFKEYSTAT_INC(in_nomem);
197 			return (ENOBUFS);
198 		}
199 	}
200 	if (m->m_len >= sizeof(struct sadb_msg)) {
201 		struct sadb_msg *msg;
202 		msg = mtod(m, struct sadb_msg *);
203 		PFKEYSTAT_INC(in_msgtype[msg->sadb_msg_type]);
204 	}
205 	KEYSOCK_LOCK();
206 	LIST_FOREACH(kp, &V_keycb_list, kp_next) {
207 		/*
208 		 * If you are in promiscuous mode, and when you get broadcasted
209 		 * reply, you'll get two PF_KEY messages.
210 		 * (based on pf_key@inner.net message on 14 Oct 1998)
211 		 */
212 		if (kp->kp_promisc) {
213 			n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
214 			if (n != NULL)
215 				key_sendup0(kp, n, 1);
216 			else
217 				PFKEYSTAT_INC(in_nomem);
218 		}
219 
220 		/* the exact target will be processed later */
221 		if (so != NULL && so->so_pcb == kp)
222 			continue;
223 
224 		if (target == KEY_SENDUP_ONE || (target ==
225 		    KEY_SENDUP_REGISTERED && kp->kp_registered == 0))
226 			continue;
227 
228 		/* KEY_SENDUP_ALL + KEY_SENDUP_REGISTERED */
229 		n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
230 		if (n == NULL) {
231 			PFKEYSTAT_INC(in_nomem);
232 			/* Try send to another socket */
233 			continue;
234 		}
235 
236 		if (key_sendup0(kp, n, 0) == 0)
237 			PFKEYSTAT_INC(in_msgtarget[target]);
238 	}
239 
240 	if (so)	{ /* KEY_SENDUP_ONE */
241 		error = key_sendup0(so->so_pcb, m, 0);
242 		if (error == 0)
243 			PFKEYSTAT_INC(in_msgtarget[KEY_SENDUP_ONE]);
244 	} else {
245 		error = 0;
246 		m_freem(m);
247 	}
248 	KEYSOCK_UNLOCK();
249 	return (error);
250 }
251 
252 static u_long key_sendspace = 8192;
253 SYSCTL_ULONG(_net_key, OID_AUTO, sendspace, CTLFLAG_RW, &key_sendspace, 0,
254     "Default key socket send space");
255 static u_long key_recvspace = 8192;
256 SYSCTL_ULONG(_net_key, OID_AUTO, recvspace, CTLFLAG_RW, &key_recvspace, 0,
257     "Default key socket receive space");
258 
259 static int
260 key_attach(struct socket *so, int proto, struct thread *td)
261 {
262 	struct keycb *kp;
263 	int error;
264 
265 	KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL"));
266 
267 	if (td != NULL) {
268 		error = priv_check(td, PRIV_NET_RAW);
269 		if (error != 0)
270 			return (error);
271 	}
272 
273 	error = soreserve(so, key_sendspace, key_recvspace);
274 	if (error != 0)
275 		return (error);
276 
277 	kp = malloc(sizeof(*kp), M_PCB, M_WAITOK);
278 	kp->kp_socket = so;
279 	kp->kp_promisc = kp->kp_registered = 0;
280 
281 	so->so_pcb = kp;
282 	so->so_options |= SO_USELOOPBACK;
283 
284 	KEYSOCK_LOCK();
285 	LIST_INSERT_HEAD(&V_keycb_list, kp, kp_next);
286 	KEYSOCK_UNLOCK();
287 	soisconnected(so);
288 
289 	return (0);
290 }
291 
292 static void
293 key_close(struct socket *so)
294 {
295 
296 	soisdisconnected(so);
297 }
298 
299 static void
300 key_detach(struct socket *so)
301 {
302 	struct keycb *kp = so->so_pcb;
303 
304 	key_freereg(so);
305 	KEYSOCK_LOCK();
306 	LIST_REMOVE(kp, kp_next);
307 	KEYSOCK_UNLOCK();
308 	free(kp, M_PCB);
309 	so->so_pcb = NULL;
310 }
311 
312 static int
313 key_shutdown(struct socket *so)
314 {
315 	socantsendmore(so);
316 	return (0);
317 }
318 
319 SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
320     "Key Family");
321 
322 static struct protosw keysw = {
323 	.pr_type =		SOCK_RAW,
324 	.pr_protocol =		PF_KEY_V2,
325 	.pr_flags =		PR_ATOMIC | PR_ADDR,
326 	.pr_abort =		key_close,
327 	.pr_attach =		key_attach,
328 	.pr_detach =		key_detach,
329 	.pr_send =		key_send,
330 	.pr_shutdown =		key_shutdown,
331 	.pr_close =		key_close,
332 };
333 
334 static struct domain keydomain = {
335 	.dom_family =		PF_KEY,
336 	.dom_name =		"key",
337 	.dom_nprotosw =		1,
338 	.dom_protosw =		{ &keysw },
339 };
340 DOMAIN_SET(key);
341