keysock.c revision 189106
1/*	$FreeBSD: head/sys/netipsec/keysock.c 189106 2009-02-27 14:12:05Z bz $	*/
2/*	$KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $	*/
3
4/*-
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include "opt_ipsec.h"
34#include "opt_route.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#include <sys/vimage.h>
55
56#include <net/if.h>
57#include <net/raw_cb.h>
58#include <net/route.h>
59#include <net/vnet.h>
60
61#include <netinet/in.h>
62
63#include <net/pfkeyv2.h>
64#include <netipsec/key.h>
65#include <netipsec/keysock.h>
66#include <netipsec/key_debug.h>
67#include <netipsec/ipsec.h>
68
69#include <machine/stdarg.h>
70
71#ifdef VIMAGE_GLOBALS
72static struct key_cb key_cb;
73struct pfkeystat pfkeystat;
74#endif
75
76static struct sockaddr key_src = { 2, PF_KEY };
77
78static int key_sendup0 __P((struct rawcb *, struct mbuf *, int));
79
80/*
81 * key_output()
82 */
83int
84key_output(struct mbuf *m, struct socket *so)
85{
86	INIT_VNET_IPSEC(curvnet);
87	struct sadb_msg *msg;
88	int len, error = 0;
89
90	if (m == 0)
91		panic("%s: NULL pointer was passed.\n", __func__);
92
93	V_pfkeystat.out_total++;
94	V_pfkeystat.out_bytes += m->m_pkthdr.len;
95
96	len = m->m_pkthdr.len;
97	if (len < sizeof(struct sadb_msg)) {
98		V_pfkeystat.out_tooshort++;
99		error = EINVAL;
100		goto end;
101	}
102
103	if (m->m_len < sizeof(struct sadb_msg)) {
104		if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
105			V_pfkeystat.out_nomem++;
106			error = ENOBUFS;
107			goto end;
108		}
109	}
110
111	M_ASSERTPKTHDR(m);
112
113	KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
114
115	msg = mtod(m, struct sadb_msg *);
116	V_pfkeystat.out_msgtype[msg->sadb_msg_type]++;
117	if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
118		V_pfkeystat.out_invlen++;
119		error = EINVAL;
120		goto end;
121	}
122
123	error = key_parse(m, so);
124	m = NULL;
125end:
126	if (m)
127		m_freem(m);
128	return error;
129}
130
131/*
132 * send message to the socket.
133 */
134static int
135key_sendup0(rp, m, promisc)
136	struct rawcb *rp;
137	struct mbuf *m;
138	int promisc;
139{
140	INIT_VNET_IPSEC(curvnet);
141	int error;
142
143	if (promisc) {
144		struct sadb_msg *pmsg;
145
146		M_PREPEND(m, sizeof(struct sadb_msg), M_DONTWAIT);
147		if (m && m->m_len < sizeof(struct sadb_msg))
148			m = m_pullup(m, sizeof(struct sadb_msg));
149		if (!m) {
150			V_pfkeystat.in_nomem++;
151			m_freem(m);
152			return ENOBUFS;
153		}
154		m->m_pkthdr.len += sizeof(*pmsg);
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		V_pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
164	}
165
166	if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src,
167	    m, NULL)) {
168		V_pfkeystat.in_nomem++;
169		m_freem(m);
170		error = ENOBUFS;
171	} else
172		error = 0;
173	sorwakeup(rp->rcb_socket);
174	return error;
175}
176
177/* XXX this interface should be obsoleted. */
178int
179key_sendup(so, msg, len, target)
180	struct socket *so;
181	struct sadb_msg *msg;
182	u_int len;
183	int target;	/*target of the resulting message*/
184{
185	INIT_VNET_IPSEC(curvnet);
186	struct mbuf *m, *n, *mprev;
187	int tlen;
188
189	/* sanity check */
190	if (so == 0 || msg == 0)
191		panic("%s: NULL pointer was passed.\n", __func__);
192
193	KEYDEBUG(KEYDEBUG_KEY_DUMP,
194		printf("%s: \n", __func__);
195		kdebug_sadb(msg));
196
197	/*
198	 * we increment statistics here, just in case we have ENOBUFS
199	 * in this function.
200	 */
201	V_pfkeystat.in_total++;
202	V_pfkeystat.in_bytes += len;
203	V_pfkeystat.in_msgtype[msg->sadb_msg_type]++;
204
205	/*
206	 * Get mbuf chain whenever possible (not clusters),
207	 * to save socket buffer.  We'll be generating many SADB_ACQUIRE
208	 * messages to listening key sockets.  If we simply allocate clusters,
209	 * sbappendaddr() will raise ENOBUFS due to too little sbspace().
210	 * sbspace() computes # of actual data bytes AND mbuf region.
211	 *
212	 * TODO: SADB_ACQUIRE filters should be implemented.
213	 */
214	tlen = len;
215	m = mprev = NULL;
216	while (tlen > 0) {
217		if (tlen == len) {
218			MGETHDR(n, M_DONTWAIT, MT_DATA);
219			if (n == NULL) {
220				V_pfkeystat.in_nomem++;
221				return ENOBUFS;
222			}
223			n->m_len = MHLEN;
224		} else {
225			MGET(n, M_DONTWAIT, MT_DATA);
226			if (n == NULL) {
227				V_pfkeystat.in_nomem++;
228				return ENOBUFS;
229			}
230			n->m_len = MLEN;
231		}
232		if (tlen >= MCLBYTES) {	/*XXX better threshold? */
233			MCLGET(n, M_DONTWAIT);
234			if ((n->m_flags & M_EXT) == 0) {
235				m_free(n);
236				m_freem(m);
237				V_pfkeystat.in_nomem++;
238				return ENOBUFS;
239			}
240			n->m_len = MCLBYTES;
241		}
242
243		if (tlen < n->m_len)
244			n->m_len = tlen;
245		n->m_next = NULL;
246		if (m == NULL)
247			m = mprev = n;
248		else {
249			mprev->m_next = n;
250			mprev = n;
251		}
252		tlen -= n->m_len;
253		n = NULL;
254	}
255	m->m_pkthdr.len = len;
256	m->m_pkthdr.rcvif = NULL;
257	m_copyback(m, 0, len, (caddr_t)msg);
258
259	/* avoid duplicated statistics */
260	V_pfkeystat.in_total--;
261	V_pfkeystat.in_bytes -= len;
262	V_pfkeystat.in_msgtype[msg->sadb_msg_type]--;
263
264	return key_sendup_mbuf(so, m, target);
265}
266
267/* so can be NULL if target != KEY_SENDUP_ONE */
268int
269key_sendup_mbuf(so, m, target)
270	struct socket *so;
271	struct mbuf *m;
272	int target;
273{
274	INIT_VNET_NET(curvnet);
275	INIT_VNET_IPSEC(curvnet);
276	struct mbuf *n;
277	struct keycb *kp;
278	int sendup;
279	struct rawcb *rp;
280	int error = 0;
281
282	if (m == NULL)
283		panic("key_sendup_mbuf: NULL pointer was passed.\n");
284	if (so == NULL && target == KEY_SENDUP_ONE)
285		panic("%s: NULL pointer was passed.\n", __func__);
286
287	V_pfkeystat.in_total++;
288	V_pfkeystat.in_bytes += m->m_pkthdr.len;
289	if (m->m_len < sizeof(struct sadb_msg)) {
290		m = m_pullup(m, sizeof(struct sadb_msg));
291		if (m == NULL) {
292			V_pfkeystat.in_nomem++;
293			return ENOBUFS;
294		}
295	}
296	if (m->m_len >= sizeof(struct sadb_msg)) {
297		struct sadb_msg *msg;
298		msg = mtod(m, struct sadb_msg *);
299		V_pfkeystat.in_msgtype[msg->sadb_msg_type]++;
300	}
301	mtx_lock(&rawcb_mtx);
302	LIST_FOREACH(rp, &V_rawcb_list, list)
303	{
304		if (rp->rcb_proto.sp_family != PF_KEY)
305			continue;
306		if (rp->rcb_proto.sp_protocol
307		 && rp->rcb_proto.sp_protocol != PF_KEY_V2) {
308			continue;
309		}
310
311		kp = (struct keycb *)rp;
312
313		/*
314		 * If you are in promiscuous mode, and when you get broadcasted
315		 * reply, you'll get two PF_KEY messages.
316		 * (based on pf_key@inner.net message on 14 Oct 1998)
317		 */
318		if (((struct keycb *)rp)->kp_promisc) {
319			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
320				(void)key_sendup0(rp, n, 1);
321				n = NULL;
322			}
323		}
324
325		/* the exact target will be processed later */
326		if (so && sotorawcb(so) == rp)
327			continue;
328
329		sendup = 0;
330		switch (target) {
331		case KEY_SENDUP_ONE:
332			/* the statement has no effect */
333			if (so && sotorawcb(so) == rp)
334				sendup++;
335			break;
336		case KEY_SENDUP_ALL:
337			sendup++;
338			break;
339		case KEY_SENDUP_REGISTERED:
340			if (kp->kp_registered)
341				sendup++;
342			break;
343		}
344		V_pfkeystat.in_msgtarget[target]++;
345
346		if (!sendup)
347			continue;
348
349		if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
350			m_freem(m);
351			V_pfkeystat.in_nomem++;
352			mtx_unlock(&rawcb_mtx);
353			return ENOBUFS;
354		}
355
356		if ((error = key_sendup0(rp, n, 0)) != 0) {
357			m_freem(m);
358			mtx_unlock(&rawcb_mtx);
359			return error;
360		}
361
362		n = NULL;
363	}
364
365	if (so) {
366		error = key_sendup0(sotorawcb(so), m, 0);
367		m = NULL;
368	} else {
369		error = 0;
370		m_freem(m);
371	}
372	mtx_unlock(&rawcb_mtx);
373	return error;
374}
375
376/*
377 * key_abort()
378 * derived from net/rtsock.c:rts_abort()
379 */
380static void
381key_abort(struct socket *so)
382{
383	raw_usrreqs.pru_abort(so);
384}
385
386/*
387 * key_attach()
388 * derived from net/rtsock.c:rts_attach()
389 */
390static int
391key_attach(struct socket *so, int proto, struct thread *td)
392{
393	INIT_VNET_IPSEC(curvnet);
394	struct keycb *kp;
395	int error;
396
397	KASSERT(so->so_pcb == NULL, ("key_attach: so_pcb != NULL"));
398
399	if (td != NULL) {
400		error = priv_check(td, PRIV_NET_RAW);
401		if (error)
402			return error;
403	}
404
405	/* XXX */
406	kp = malloc(sizeof *kp, M_PCB, M_WAITOK | M_ZERO);
407	if (kp == 0)
408		return ENOBUFS;
409
410	so->so_pcb = (caddr_t)kp;
411	error = raw_attach(so, proto);
412	kp = (struct keycb *)sotorawcb(so);
413	if (error) {
414		free(kp, M_PCB);
415		so->so_pcb = (caddr_t) 0;
416		return error;
417	}
418
419	kp->kp_promisc = kp->kp_registered = 0;
420
421	if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
422		V_key_cb.key_count++;
423	V_key_cb.any_count++;
424	soisconnected(so);
425	so->so_options |= SO_USELOOPBACK;
426
427	return 0;
428}
429
430/*
431 * key_bind()
432 * derived from net/rtsock.c:rts_bind()
433 */
434static int
435key_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
436{
437  return EINVAL;
438}
439
440/*
441 * key_close()
442 * derived from net/rtsock.c:rts_close().
443 */
444static void
445key_close(struct socket *so)
446{
447
448	raw_usrreqs.pru_close(so);
449}
450
451/*
452 * key_connect()
453 * derived from net/rtsock.c:rts_connect()
454 */
455static int
456key_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
457{
458	return EINVAL;
459}
460
461/*
462 * key_detach()
463 * derived from net/rtsock.c:rts_detach()
464 */
465static void
466key_detach(struct socket *so)
467{
468	INIT_VNET_IPSEC(curvnet);
469	struct keycb *kp = (struct keycb *)sotorawcb(so);
470
471	KASSERT(kp != NULL, ("key_detach: kp == NULL"));
472	if (kp->kp_raw.rcb_proto.sp_protocol
473	    == PF_KEY) /* XXX: AF_KEY */
474		V_key_cb.key_count--;
475	V_key_cb.any_count--;
476
477	key_freereg(so);
478	raw_usrreqs.pru_detach(so);
479}
480
481/*
482 * key_disconnect()
483 * derived from net/rtsock.c:key_disconnect()
484 */
485static int
486key_disconnect(struct socket *so)
487{
488	return(raw_usrreqs.pru_disconnect(so));
489}
490
491/*
492 * key_peeraddr()
493 * derived from net/rtsock.c:rts_peeraddr()
494 */
495static int
496key_peeraddr(struct socket *so, struct sockaddr **nam)
497{
498	return(raw_usrreqs.pru_peeraddr(so, nam));
499}
500
501/*
502 * key_send()
503 * derived from net/rtsock.c:rts_send()
504 */
505static int
506key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
507	 struct mbuf *control, struct thread *td)
508{
509	return(raw_usrreqs.pru_send(so, flags, m, nam, control, td));
510}
511
512/*
513 * key_shutdown()
514 * derived from net/rtsock.c:rts_shutdown()
515 */
516static int
517key_shutdown(struct socket *so)
518{
519	return(raw_usrreqs.pru_shutdown(so));
520}
521
522/*
523 * key_sockaddr()
524 * derived from net/rtsock.c:rts_sockaddr()
525 */
526static int
527key_sockaddr(struct socket *so, struct sockaddr **nam)
528{
529	return(raw_usrreqs.pru_sockaddr(so, nam));
530}
531
532struct pr_usrreqs key_usrreqs = {
533	.pru_abort =		key_abort,
534	.pru_attach =		key_attach,
535	.pru_bind =		key_bind,
536	.pru_connect =		key_connect,
537	.pru_detach =		key_detach,
538	.pru_disconnect =	key_disconnect,
539	.pru_peeraddr =		key_peeraddr,
540	.pru_send =		key_send,
541	.pru_shutdown =		key_shutdown,
542	.pru_sockaddr =		key_sockaddr,
543	.pru_close =		key_close,
544};
545
546/* sysctl */
547SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family");
548
549/*
550 * Definitions of protocols supported in the KEY domain.
551 */
552
553extern struct domain keydomain;
554
555struct protosw keysw[] = {
556{
557	.pr_type =		SOCK_RAW,
558	.pr_domain =		&keydomain,
559	.pr_protocol =		PF_KEY_V2,
560	.pr_flags =		PR_ATOMIC|PR_ADDR,
561	.pr_output =		key_output,
562	.pr_ctlinput =		raw_ctlinput,
563	.pr_init =		raw_init,
564	.pr_usrreqs =		&key_usrreqs
565}
566};
567
568static void
569key_init0(void)
570{
571	INIT_VNET_IPSEC(curvnet);
572
573	bzero((caddr_t)&V_key_cb, sizeof(V_key_cb));
574	ipsec_init();
575	key_init();
576}
577
578struct domain keydomain = {
579	.dom_family =		PF_KEY,
580	.dom_name =		"key",
581	.dom_init =		key_init0,
582	.dom_protosw =		keysw,
583	.dom_protoswNPROTOSW =	&keysw[sizeof(keysw)/sizeof(keysw[0])]
584};
585
586DOMAIN_SET(key);
587