xref: /freebsd/sys/netipsec/keysock.c (revision ac175bd33a21b7f357cffe37117dc5afa6d7c5fb)
1 /*	$FreeBSD$	*/
2 /*	$KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $	*/
3 
4 /*-
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the project nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "opt_ipsec.h"
36 
37 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/domain.h>
42 #include <sys/errno.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/mutex.h>
48 #include <sys/priv.h>
49 #include <sys/protosw.h>
50 #include <sys/signalvar.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/systm.h>
55 
56 #include <net/if.h>
57 #include <net/vnet.h>
58 
59 #include <netinet/in.h>
60 
61 #include <net/pfkeyv2.h>
62 #include <netipsec/key.h>
63 #include <netipsec/keysock.h>
64 #include <netipsec/key_debug.h>
65 #include <netipsec/ipsec.h>
66 
67 #include <machine/stdarg.h>
68 
69 static struct mtx keysock_mtx;
70 MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF);
71 
72 #define	KEYSOCK_LOCK()		mtx_lock(&keysock_mtx)
73 #define	KEYSOCK_UNLOCK()	mtx_unlock(&keysock_mtx)
74 
75 VNET_DEFINE_STATIC(LIST_HEAD(, keycb), 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)
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 || (
225 		    target == 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)
270 			return error;
271 	}
272 
273 	error = soreserve(so, key_sendspace, key_recvspace);
274 	if (error)
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 
316 	socantsendmore(so);
317 	return (0);
318 }
319 
320 struct pr_usrreqs key_usrreqs = {
321 	.pru_abort =		key_close,
322 	.pru_attach =		key_attach,
323 	.pru_detach =		key_detach,
324 	.pru_send =		key_send,
325 	.pru_shutdown =		key_shutdown,
326 	.pru_close =		key_close,
327 };
328 
329 /* sysctl */
330 SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
331     "Key Family");
332 
333 /*
334  * Definitions of protocols supported in the KEY domain.
335  */
336 
337 extern struct domain keydomain;
338 
339 struct protosw keysw[] = {
340 {
341 	.pr_type =		SOCK_RAW,
342 	.pr_domain =		&keydomain,
343 	.pr_protocol =		PF_KEY_V2,
344 	.pr_flags =		PR_ATOMIC|PR_ADDR,
345 	.pr_usrreqs =		&key_usrreqs
346 }
347 };
348 
349 struct domain keydomain = {
350 	.dom_family =		PF_KEY,
351 	.dom_name =		"key",
352 	.dom_protosw =		keysw,
353 	.dom_protoswNPROTOSW =	&keysw[nitems(keysw)]
354 };
355 DOMAIN_SET(key);
356