xref: /netbsd-src/sys/netipsec/keysock.c (revision da5f4674a3fc214be3572d358b66af40ab9401e7)
1 /*	$NetBSD: keysock.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $	*/
2 /*	$FreeBSD: src/sys/netipsec/keysock.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $	*/
3 /*	$KAME: keysock.c,v 1.25 2001/08/13 20:07:41 itojun Exp $	*/
4 
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 <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: keysock.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $");
36 
37 #include "opt_ipsec.h"
38 
39 /* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/domain.h>
44 #include <sys/errno.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.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/raw_cb.h>
56 #include <net/route.h>
57 
58 #include <net/pfkeyv2.h>
59 #include <netipsec/key.h>
60 #include <netipsec/keysock.h>
61 #include <netipsec/key_debug.h>
62 
63 #include <netipsec/ipsec_osdep.h>
64 
65 #include <machine/stdarg.h>
66 
67 typedef int	pr_output_t (struct mbuf *, struct socket *);
68 
69 struct key_cb {
70 	int key_count;
71 	int any_count;
72 };
73 static struct key_cb key_cb;
74 
75 static struct sockaddr key_dst = { 2, PF_KEY, };
76 static struct sockaddr key_src = { 2, PF_KEY, };
77 
78 static int key_sendup0 __P((struct rawcb *, struct mbuf *, int));
79 
80 struct pfkeystat pfkeystat;
81 
82 /*
83  * key_output()
84  */
85 int
86 #if __STDC__
87 key_output(struct mbuf *m, ...)
88 #else
89 key_output(m, va_alist)
90 	struct mbuf *m;
91 	va_dcl
92 #endif
93 {
94 	struct sadb_msg *msg;
95 	int len, error = 0;
96 	int s;
97 	struct socket *so;
98 	va_list ap;
99 
100 	va_start(ap, m);
101 	so = va_arg(ap, struct socket *);
102 	va_end(ap);
103 
104 	if (m == 0)
105 		panic("key_output: NULL pointer was passed.\n");
106 
107 	pfkeystat.out_total++;
108 	pfkeystat.out_bytes += m->m_pkthdr.len;
109 
110 	len = m->m_pkthdr.len;
111 	if (len < sizeof(struct sadb_msg)) {
112 		pfkeystat.out_tooshort++;
113 		error = EINVAL;
114 		goto end;
115 	}
116 
117 	if (m->m_len < sizeof(struct sadb_msg)) {
118 		if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
119 			pfkeystat.out_nomem++;
120 			error = ENOBUFS;
121 			goto end;
122 		}
123 	}
124 
125 	if ((m->m_flags & M_PKTHDR) == 0)
126 		panic("key_output: not M_PKTHDR ??");
127 
128 	KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
129 
130 	msg = mtod(m, struct sadb_msg *);
131 	pfkeystat.out_msgtype[msg->sadb_msg_type]++;
132 	if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
133 		pfkeystat.out_invlen++;
134 		error = EINVAL;
135 		goto end;
136 	}
137 
138 	/*XXX giant lock*/
139 	s = splsoftnet();
140 	error = key_parse(m, so);
141 	m = NULL;
142 	splx(s);
143 end:
144 	if (m)
145 		m_freem(m);
146 	return error;
147 }
148 
149 /*
150  * send message to the socket.
151  */
152 static int
153 key_sendup0(rp, m, promisc)
154 	struct rawcb *rp;
155 	struct mbuf *m;
156 	int promisc;
157 {
158 	int error;
159 
160 	if (promisc) {
161 		struct sadb_msg *pmsg;
162 
163 		M_PREPEND(m, sizeof(struct sadb_msg), M_DONTWAIT);
164 		if (m && m->m_len < sizeof(struct sadb_msg))
165 			m = m_pullup(m, sizeof(struct sadb_msg));
166 		if (!m) {
167 			pfkeystat.in_nomem++;
168 			m_freem(m);
169 			return ENOBUFS;
170 		}
171 		m->m_pkthdr.len += sizeof(*pmsg);
172 
173 		pmsg = mtod(m, struct sadb_msg *);
174 		bzero(pmsg, sizeof(*pmsg));
175 		pmsg->sadb_msg_version = PF_KEY_V2;
176 		pmsg->sadb_msg_type = SADB_X_PROMISC;
177 		pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
178 		/* pid and seq? */
179 
180 		pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
181 	}
182 
183 	if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src,
184 	    m, NULL)) {
185 		pfkeystat.in_nomem++;
186 		m_freem(m);
187 		error = ENOBUFS;
188 	} else
189 		error = 0;
190 	sorwakeup(rp->rcb_socket);
191 	return error;
192 }
193 
194 /* XXX this interface should be obsoleted. */
195 int
196 key_sendup(so, msg, len, target)
197 	struct socket *so;
198 	struct sadb_msg *msg;
199 	u_int len;
200 	int target;	/*target of the resulting message*/
201 {
202 	struct mbuf *m, *n, *mprev;
203 	int tlen;
204 
205 	/* sanity check */
206 	if (so == 0 || msg == 0)
207 		panic("key_sendup: NULL pointer was passed.\n");
208 
209 	KEYDEBUG(KEYDEBUG_KEY_DUMP,
210 		printf("key_sendup: \n");
211 		kdebug_sadb(msg));
212 
213 	/*
214 	 * we increment statistics here, just in case we have ENOBUFS
215 	 * in this function.
216 	 */
217 	pfkeystat.in_total++;
218 	pfkeystat.in_bytes += len;
219 	pfkeystat.in_msgtype[msg->sadb_msg_type]++;
220 
221 	/*
222 	 * Get mbuf chain whenever possible (not clusters),
223 	 * to save socket buffer.  We'll be generating many SADB_ACQUIRE
224 	 * messages to listening key sockets.  If we simply allocate clusters,
225 	 * sbappendaddr() will raise ENOBUFS due to too little sbspace().
226 	 * sbspace() computes # of actual data bytes AND mbuf region.
227 	 *
228 	 * TODO: SADB_ACQUIRE filters should be implemented.
229 	 */
230 	tlen = len;
231 	m = mprev = NULL;
232 	while (tlen > 0) {
233 		if (tlen == len) {
234 			MGETHDR(n, M_DONTWAIT, MT_DATA);
235 			n->m_len = MHLEN;
236 		} else {
237 			MGET(n, M_DONTWAIT, MT_DATA);
238 			n->m_len = MLEN;
239 		}
240 		if (!n) {
241 			pfkeystat.in_nomem++;
242 			return ENOBUFS;
243 		}
244 		if (tlen >= MCLBYTES) {	/*XXX better threshold? */
245 			MCLGET(n, M_DONTWAIT);
246 			if ((n->m_flags & M_EXT) == 0) {
247 				m_free(n);
248 				m_freem(m);
249 				pfkeystat.in_nomem++;
250 				return ENOBUFS;
251 			}
252 			n->m_len = MCLBYTES;
253 		}
254 
255 		if (tlen < n->m_len)
256 			n->m_len = tlen;
257 		n->m_next = NULL;
258 		if (m == NULL)
259 			m = mprev = n;
260 		else {
261 			mprev->m_next = n;
262 			mprev = n;
263 		}
264 		tlen -= n->m_len;
265 		n = NULL;
266 	}
267 	m->m_pkthdr.len = len;
268 	m->m_pkthdr.rcvif = NULL;
269 	m_copyback(m, 0, len, (caddr_t)msg);
270 
271 	/* avoid duplicated statistics */
272 	pfkeystat.in_total--;
273 	pfkeystat.in_bytes -= len;
274 	pfkeystat.in_msgtype[msg->sadb_msg_type]--;
275 
276 	return key_sendup_mbuf(so, m, target);
277 }
278 
279 /* so can be NULL if target != KEY_SENDUP_ONE */
280 int
281 key_sendup_mbuf(so, m, target)
282 	struct socket *so;
283 	struct mbuf *m;
284 	int target;
285 {
286 	struct mbuf *n;
287 	struct keycb *kp;
288 	int sendup;
289 	struct rawcb *rp;
290 	int error = 0;
291 
292 	if (m == NULL)
293 		panic("key_sendup_mbuf: NULL pointer was passed.\n");
294 	if (so == NULL && target == KEY_SENDUP_ONE)
295 		panic("key_sendup_mbuf: NULL pointer was passed.\n");
296 
297 	pfkeystat.in_total++;
298 	pfkeystat.in_bytes += m->m_pkthdr.len;
299 	if (m->m_len < sizeof(struct sadb_msg)) {
300 #if 1
301 		m = m_pullup(m, sizeof(struct sadb_msg));
302 		if (m == NULL) {
303 			pfkeystat.in_nomem++;
304 			return ENOBUFS;
305 		}
306 #else
307 		/* don't bother pulling it up just for stats */
308 #endif
309 	}
310 	if (m->m_len >= sizeof(struct sadb_msg)) {
311 		struct sadb_msg *msg;
312 		msg = mtod(m, struct sadb_msg *);
313 		pfkeystat.in_msgtype[msg->sadb_msg_type]++;
314 	}
315 
316 	LIST_FOREACH(rp, &rawcb_list, rcb_list)
317 	{
318 		if (rp->rcb_proto.sp_family != PF_KEY)
319 			continue;
320 		if (rp->rcb_proto.sp_protocol
321 		 && rp->rcb_proto.sp_protocol != PF_KEY_V2) {
322 			continue;
323 		}
324 
325 		kp = (struct keycb *)rp;
326 
327 		/*
328 		 * If you are in promiscuous mode, and when you get broadcasted
329 		 * reply, you'll get two PF_KEY messages.
330 		 * (based on pf_key@inner.net message on 14 Oct 1998)
331 		 */
332 		if (((struct keycb *)rp)->kp_promisc) {
333 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
334 				(void)key_sendup0(rp, n, 1);
335 				n = NULL;
336 			}
337 		}
338 
339 		/* the exact target will be processed later */
340 		if (so && sotorawcb(so) == rp)
341 			continue;
342 
343 		sendup = 0;
344 		switch (target) {
345 		case KEY_SENDUP_ONE:
346 			/* the statement has no effect */
347 			if (so && sotorawcb(so) == rp)
348 				sendup++;
349 			break;
350 		case KEY_SENDUP_ALL:
351 			sendup++;
352 			break;
353 		case KEY_SENDUP_REGISTERED:
354 			if (kp->kp_registered)
355 				sendup++;
356 			break;
357 		}
358 		pfkeystat.in_msgtarget[target]++;
359 
360 		if (!sendup)
361 			continue;
362 
363 		if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
364 			m_freem(m);
365 			pfkeystat.in_nomem++;
366 			return ENOBUFS;
367 		}
368 
369 		if ((error = key_sendup0(rp, n, 0)) != 0) {
370 			m_freem(m);
371 			return error;
372 		}
373 
374 		n = NULL;
375 	}
376 
377 	if (so) {
378 		error = key_sendup0(sotorawcb(so), m, 0);
379 		m = NULL;
380 	} else {
381 		error = 0;
382 		m_freem(m);
383 	}
384 	return error;
385 }
386 
387 #ifdef __FreeBSD__
388 
389 /*
390  * key_abort()
391  * derived from net/rtsock.c:rts_abort()
392  */
393 static int
394 key_abort(struct socket *so)
395 {
396 	int s, error;
397 	s = splnet(); 	/* FreeBSD */
398 	error = raw_usrreqs.pru_abort(so);
399 	splx(s);
400 	return error;
401 }
402 
403 /*
404  * key_attach()
405  * derived from net/rtsock.c:rts_attach()
406  */
407 static int
408 key_attach(struct socket *so, int proto, struct proc *td)
409 {
410 	struct keycb *kp;
411 	int s, error;
412 
413 	if (sotorawcb(so) != 0)
414 		return EISCONN;	/* XXX panic? */
415 	kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK|M_ZERO); /* XXX */
416 	if (kp == 0)
417 		return ENOBUFS;
418 
419 	/*
420 	 * The spl[soft]net() is necessary to block protocols from sending
421 	 * error notifications (like RTM_REDIRECT or RTM_LOSING) while
422 	 * this PCB is extant but incompletely initialized.
423 	 * Probably we should try to do more of this work beforehand and
424 	 * eliminate the spl.
425 	 */
426 	s = splnet();	/* FreeBSD */
427 	so->so_pcb = (caddr_t)kp;
428 	error = raw_usrreqs.pru_attach(so, proto, td);
429 	kp = (struct keycb *)sotorawcb(so);
430 	if (error) {
431 		free(kp, M_PCB);
432 		so->so_pcb = (caddr_t) 0;
433 		splx(s);
434 		return error;
435 	}
436 
437 	kp->kp_promisc = kp->kp_registered = 0;
438 
439 	if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
440 		key_cb.key_count++;
441 	key_cb.any_count++;
442 	kp->kp_raw.rcb_laddr = &key_src;
443 	kp->kp_raw.rcb_faddr = &key_dst;
444 	soisconnected(so);
445 	so->so_options |= SO_USELOOPBACK;
446 
447 	splx(s);
448 	return 0;
449 }
450 
451 /*
452  * key_bind()
453  * derived from net/rtsock.c:rts_bind()
454  */
455 static int
456 key_bind(struct socket *so, struct sockaddr *nam, struct proc *td)
457 {
458 	int s, error;
459 	s = splnet();	/* FreeBSD */
460 	error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
461 	splx(s);
462 	return error;
463 }
464 
465 /*
466  * key_connect()
467  * derived from net/rtsock.c:rts_connect()
468  */
469 static int
470 key_connect(struct socket *so, struct sockaddr *nam, struct proc *td)
471 {
472 	int s, error;
473 	s = splnet();	/* FreeBSD */
474 	error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
475 	splx(s);
476 	return error;
477 }
478 
479 /*
480  * key_detach()
481  * derived from net/rtsock.c:rts_detach()
482  */
483 static int
484 key_detach(struct socket *so)
485 {
486 	struct keycb *kp = (struct keycb *)sotorawcb(so);
487 	int s, error;
488 
489 	s = splnet();	/* FreeBSD */
490 	if (kp != 0) {
491 		if (kp->kp_raw.rcb_proto.sp_protocol
492 		    == PF_KEY) /* XXX: AF_KEY */
493 			key_cb.key_count--;
494 		key_cb.any_count--;
495 
496 		key_freereg(so);
497 	}
498 	error = raw_usrreqs.pru_detach(so);
499 	splx(s);
500 	return error;
501 }
502 
503 /*
504  * key_disconnect()
505  * derived from net/rtsock.c:key_disconnect()
506  */
507 static int
508 key_disconnect(struct socket *so)
509 {
510 	int s, error;
511 	s = splnet();	/* FreeBSD */
512 	error = raw_usrreqs.pru_disconnect(so);
513 	splx(s);
514 	return error;
515 }
516 
517 /*
518  * key_peeraddr()
519  * derived from net/rtsock.c:rts_peeraddr()
520  */
521 static int
522 key_peeraddr(struct socket *so, struct sockaddr **nam)
523 {
524 	int s, error;
525 	s = splnet();	/* FreeBSD */
526 	error = raw_usrreqs.pru_peeraddr(so, nam);
527 	splx(s);
528 	return error;
529 }
530 
531 /*
532  * key_send()
533  * derived from net/rtsock.c:rts_send()
534  */
535 static int
536 key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
537 	 struct mbuf *control, struct proc *td)
538 {
539 	int s, error;
540 	s = splnet();	/* FreeBSD */
541 	error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
542 	splx(s);
543 	return error;
544 }
545 
546 /*
547  * key_shutdown()
548  * derived from net/rtsock.c:rts_shutdown()
549  */
550 static int
551 key_shutdown(struct socket *so)
552 {
553 	int s, error;
554 	s = splnet();	/* FreeBSD */
555 	error = raw_usrreqs.pru_shutdown(so);
556 	splx(s);
557 	return error;
558 }
559 
560 /*
561  * key_sockaddr()
562  * derived from net/rtsock.c:rts_sockaddr()
563  */
564 static int
565 key_sockaddr(struct socket *so, struct sockaddr **nam)
566 {
567 	int s, error;
568 	s = splnet();	/* FreeBSD */
569 	error = raw_usrreqs.pru_sockaddr(so, nam);
570 	splx(s);
571 	return error;
572 }
573 #else /*!__FreeBSD__ -- traditional proto_usrreq() switch */
574 
575 /*
576  * key_usrreq()
577  * derived from net/rtsock.c:route_usrreq()
578  */
579 int
580 key_usrreq(so, req, m, nam, control, p)
581 	struct socket *so;
582 	int req;
583 	struct mbuf *m, *nam, *control;
584 	struct proc *p;
585 {
586 	int error = 0;
587 	struct keycb *kp = (struct keycb *)sotorawcb(so);
588 	int s;
589 
590 	s = splsoftnet();
591 	if (req == PRU_ATTACH) {
592 		kp = (struct keycb *)malloc(sizeof(*kp), M_PCB, M_WAITOK);
593 		so->so_pcb = (caddr_t)kp;
594 		if (so->so_pcb)
595 			bzero(so->so_pcb, sizeof(*kp));
596 	}
597 	if (req == PRU_DETACH && kp) {
598 		int af = kp->kp_raw.rcb_proto.sp_protocol;
599 		if (af == PF_KEY) /* XXX: AF_KEY */
600 			key_cb.key_count--;
601 		key_cb.any_count--;
602 
603 		key_freereg(so);
604 	}
605 
606 	error = raw_usrreq(so, req, m, nam, control, p);
607 	m = control = NULL;	/* reclaimed in raw_usrreq */
608 	kp = (struct keycb *)sotorawcb(so);
609 	if (req == PRU_ATTACH && kp) {
610 		int af = kp->kp_raw.rcb_proto.sp_protocol;
611 		if (error) {
612 			pfkeystat.sockerr++;
613 			free((caddr_t)kp, M_PCB);
614 			so->so_pcb = (caddr_t) 0;
615 			splx(s);
616 			return (error);
617 		}
618 
619 		kp->kp_promisc = kp->kp_registered = 0;
620 
621 		if (af == PF_KEY) /* XXX: AF_KEY */
622 			key_cb.key_count++;
623 		key_cb.any_count++;
624 		kp->kp_raw.rcb_laddr = &key_src;
625 		kp->kp_raw.rcb_faddr = &key_dst;
626 		soisconnected(so);
627 		so->so_options |= SO_USELOOPBACK;
628 	}
629 	splx(s);
630 	return (error);
631 }
632 #endif /*!__FreeBSD__*/
633 
634 /* sysctl */
635 #ifdef SYSCTL_NODE
636 SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family");
637 #endif SYSCTL_NODE
638 
639 /*
640  * Definitions of protocols supported in the KEY domain.
641  */
642 
643 /* This extern declaration is all that's common... */
644 extern struct domain keydomain;
645 
646 #ifdef __FreeBSD__
647 struct pr_usrreqs key_usrreqs = {
648 	key_abort, pru_accept_notsupp, key_attach, key_bind,
649 	key_connect,
650 	pru_connect2_notsupp, pru_control_notsupp, key_detach,
651 	key_disconnect, pru_listen_notsupp, key_peeraddr,
652 	pru_rcvd_notsupp,
653 	pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown,
654 	key_sockaddr, sosend, soreceive, sopoll
655 };
656 
657 struct protosw keysw[] = {
658 { SOCK_RAW,	&keydomain,	PF_KEY_V2,	PR_ATOMIC|PR_ADDR,
659   0,		(pr_output_t *)key_output,	raw_ctlinput, 0,
660   0,
661   raw_init,	0,		0,		0,
662   &key_usrreqs
663 }
664 };
665 
666 static void
667 key_init0(void)
668 {
669 	bzero((caddr_t)&key_cb, sizeof(key_cb));
670 	key_init();
671 }
672 
673 struct domain keydomain =
674     { PF_KEY, "key", key_init0, 0, 0,
675       keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
676 
677 DOMAIN_SET(key);
678 
679 #else /* !__FreeBSD__ */
680 
681 
682 struct protosw keysw[] = {
683 { SOCK_RAW,	&keydomain,	PF_KEY_V2,	PR_ATOMIC|PR_ADDR,
684   0,		key_output,	raw_ctlinput,	0,
685   key_usrreq,
686   raw_init,	0,		0,		0,
687   key_sysctl,
688 }
689 };
690 
691 struct domain keydomain =
692     { PF_KEY, "key", key_init, 0, 0,
693       keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
694 
695 #endif
696