1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2009-2010 Ana Kukec <anchie@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/kernel.h>
31#include <sys/malloc.h>
32#include <sys/mbuf.h>
33#include <sys/module.h>
34#include <sys/priv.h>
35#include <sys/protosw.h>
36#include <sys/sdt.h>
37#include <sys/systm.h>
38#include <sys/socket.h>
39#include <sys/sockbuf.h>
40#include <sys/socketvar.h>
41#include <sys/types.h>
42
43#include <net/route.h>
44#include <net/if.h>
45#include <net/if_var.h>
46#include <net/if_private.h>
47#include <net/vnet.h>
48
49#include <netinet/in.h>
50#include <netinet/in_kdtrace.h>
51#include <netinet/ip_var.h>
52#include <netinet/ip6.h>
53#include <netinet/icmp6.h>
54
55#include <netinet6/in6_var.h>
56#include <netinet6/nd6.h>
57#include <netinet6/scope6_var.h>
58#include <netinet6/send.h>
59
60static MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery");
61
62/*
63 * The socket used to communicate with the SeND daemon.
64 */
65VNET_DEFINE_STATIC(struct socket *, send_so);
66#define	V_send_so	VNET(send_so)
67
68u_long	send_sendspace	= 8 * (1024 + sizeof(struct sockaddr_send));
69u_long	send_recvspace	= 9216;
70
71struct mtx	send_mtx;
72#define SEND_LOCK_INIT()	mtx_init(&send_mtx, "send_mtx", NULL, MTX_DEF)
73#define SEND_LOCK()		mtx_lock(&send_mtx)
74#define SEND_UNLOCK()		mtx_unlock(&send_mtx)
75#define SEND_LOCK_DESTROY()     mtx_destroy(&send_mtx)
76
77static int
78send_attach(struct socket *so, int proto, struct thread *td)
79{
80	int error;
81
82	SEND_LOCK();
83	if (V_send_so != NULL) {
84		SEND_UNLOCK();
85		return (EEXIST);
86	}
87
88	error = priv_check(td, PRIV_NETINET_RAW);
89	if (error) {
90		SEND_UNLOCK();
91		return(error);
92	}
93
94	if (proto != IPPROTO_SEND) {
95		SEND_UNLOCK();
96		return (EPROTONOSUPPORT);
97	}
98	error = soreserve(so, send_sendspace, send_recvspace);
99	if (error) {
100		SEND_UNLOCK();
101		return(error);
102	}
103
104	V_send_so = so;
105	SEND_UNLOCK();
106
107	return (0);
108}
109
110static int
111send_output(struct mbuf *m, struct ifnet *ifp, int direction)
112{
113	struct ip6_hdr *ip6;
114	struct sockaddr_in6 dst;
115	struct icmp6_hdr *icmp6;
116	struct epoch_tracker et;
117	int icmp6len;
118	int error;
119
120	/*
121	 * Receive incoming (SeND-protected) or outgoing traffic
122	 * (SeND-validated) from the SeND user space application.
123	 */
124
125	switch (direction) {
126	case SND_IN:
127		if (m->m_len < (sizeof(struct ip6_hdr) +
128		    sizeof(struct icmp6_hdr))) {
129			m = m_pullup(m, sizeof(struct ip6_hdr) +
130			    sizeof(struct icmp6_hdr));
131			if (!m)
132				return (ENOBUFS);
133		}
134
135		/* Before passing off the mbuf record the proper interface. */
136		m->m_pkthdr.rcvif = ifp;
137
138		if (m->m_flags & M_PKTHDR)
139			icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr);
140		else
141			panic("Doh! not the first mbuf.");
142
143		ip6 = mtod(m, struct ip6_hdr *);
144		icmp6 = (struct icmp6_hdr *)(ip6 + 1);
145		error = 0;
146
147		/*
148		 * Output the packet as icmp6.c:icpm6_input() would do.
149		 * The mbuf is always consumed, so we do not have to
150		 * care about that.
151		 */
152		NET_EPOCH_ENTER(et);
153		switch (icmp6->icmp6_type) {
154		case ND_NEIGHBOR_SOLICIT:
155			nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len);
156			break;
157		case ND_NEIGHBOR_ADVERT:
158			nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len);
159			break;
160		case ND_REDIRECT:
161			icmp6_redirect_input(m, sizeof(struct ip6_hdr));
162			break;
163		case ND_ROUTER_SOLICIT:
164			nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len);
165			break;
166		case ND_ROUTER_ADVERT:
167			nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len);
168			break;
169		default:
170			m_freem(m);
171			error = ENOSYS;
172		}
173		NET_EPOCH_EXIT(et);
174
175		return (error);
176
177	case SND_OUT:
178		if (m->m_len < sizeof(struct ip6_hdr)) {
179			m = m_pullup(m, sizeof(struct ip6_hdr));
180			if (!m)
181				return (ENOBUFS);
182		}
183		ip6 = mtod(m, struct ip6_hdr *);
184		if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
185			m->m_flags |= M_MCAST;
186
187		bzero(&dst, sizeof(dst));
188		dst.sin6_family = AF_INET6;
189		dst.sin6_len = sizeof(dst);
190		dst.sin6_addr = ip6->ip6_dst;
191
192		m_clrprotoflags(m);	/* Avoid confusing lower layers. */
193
194		IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6);
195
196		/*
197		 * Output the packet as nd6.c:nd6_output_lle() would do.
198		 * The mbuf is always consumed, so we do not have to care
199		 * about that.
200		 * XXX-BZ as we added data, what about fragmenting,
201		 * if now needed?
202		 */
203		error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
204		    NULL));
205		if (error)
206			error = ENOENT;
207		return (error);
208
209	default:
210		panic("%s: direction %d neither SND_IN nor SND_OUT.",
211		     __func__, direction);
212	}
213}
214
215/*
216 * Receive a SeND message from user space to be either send out by the kernel
217 * or, with SeND ICMPv6 options removed, to be further processed by the icmp6
218 * input path.
219 */
220static int
221send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
222    struct mbuf *control, struct thread *td)
223{
224	struct sockaddr_send *sendsrc;
225	struct ifnet *ifp;
226	int error;
227
228	KASSERT(V_send_so == so, ("%s: socket %p not send socket %p",
229		__func__, so, V_send_so));
230
231	sendsrc = (struct sockaddr_send *)nam;
232	if (sendsrc->send_family != AF_INET6) {
233		error = EAFNOSUPPORT;
234		goto err;
235	}
236	if (sendsrc->send_len != sizeof(*sendsrc)) {
237		error = EINVAL;
238		goto err;
239	}
240	ifp = ifnet_byindex_ref(sendsrc->send_ifidx);
241	if (ifp == NULL) {
242		error = ENETUNREACH;
243		goto err;
244	}
245
246	error = send_output(m, ifp, sendsrc->send_direction);
247	if_rele(ifp);
248	m = NULL;
249
250err:
251	if (control != NULL)
252		m_freem(control);
253	if (m != NULL)
254		m_freem(m);
255
256	return (error);
257}
258
259static void
260send_close(struct socket *so)
261{
262
263	SEND_LOCK();
264	if (V_send_so)
265		V_send_so = NULL;
266	SEND_UNLOCK();
267}
268
269/*
270 * Send a SeND message to user space, that was either received and has to be
271 * validated or was about to be send out and has to be handled by the SEND
272 * daemon adding SeND ICMPv6 options.
273 */
274static int
275send_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused)
276{
277	struct ip6_hdr *ip6;
278	struct sockaddr_send sendsrc;
279
280	SEND_LOCK();
281	if (V_send_so == NULL) {
282		SEND_UNLOCK();
283		return (-1);
284	}
285
286	/*
287	 * Make sure to clear any possible internally embedded scope before
288	 * passing the packet to user space for SeND cryptographic signature
289	 * validation to succeed.
290	 */
291	ip6 = mtod(m, struct ip6_hdr *);
292	in6_clearscope(&ip6->ip6_src);
293	in6_clearscope(&ip6->ip6_dst);
294
295	bzero(&sendsrc, sizeof(sendsrc));
296	sendsrc.send_len = sizeof(sendsrc);
297	sendsrc.send_family = AF_INET6;
298	sendsrc.send_direction = direction;
299	sendsrc.send_ifidx = ifp->if_index;
300
301	/*
302	 * Send incoming or outgoing traffic to user space either to be
303	 * protected (outgoing) or validated (incoming) according to rfc3971.
304	 */
305	SOCKBUF_LOCK(&V_send_so->so_rcv);
306	if (sbappendaddr_locked(&V_send_so->so_rcv,
307	    (struct sockaddr *)&sendsrc, m, NULL) == 0) {
308		soroverflow_locked(V_send_so);
309		/* XXX stats. */
310		m_freem(m);
311	} else {
312		sorwakeup_locked(V_send_so);
313	}
314
315	SEND_UNLOCK();
316	return (0);
317}
318
319static struct protosw send_protosw = {
320	.pr_type =		SOCK_RAW,
321	.pr_flags =		PR_ATOMIC|PR_ADDR,
322	.pr_protocol =		IPPROTO_SEND,
323	.pr_attach =		send_attach,
324	.pr_send =		send_send,
325	.pr_detach =		send_close
326};
327
328static int
329send_modevent(module_t mod, int type, void *unused)
330{
331#ifdef __notyet__
332	VNET_ITERATOR_DECL(vnet_iter);
333#endif
334	int error;
335
336	switch (type) {
337	case MOD_LOAD:
338		SEND_LOCK_INIT();
339
340		error = protosw_register(&inet6domain, &send_protosw);
341		if (error != 0) {
342			printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n",
343			   __func__, __LINE__, error);
344			SEND_LOCK_DESTROY();
345			break;
346		}
347		send_sendso_input_hook = send_input;
348		break;
349	case MOD_UNLOAD:
350		/* Do not allow unloading w/o locking. */
351		return (EBUSY);
352#ifdef __notyet__
353		VNET_LIST_RLOCK_NOSLEEP();
354		SEND_LOCK();
355		VNET_FOREACH(vnet_iter) {
356			CURVNET_SET(vnet_iter);
357			if (V_send_so != NULL) {
358				CURVNET_RESTORE();
359				SEND_UNLOCK();
360				VNET_LIST_RUNLOCK_NOSLEEP();
361				return (EBUSY);
362			}
363			CURVNET_RESTORE();
364		}
365		SEND_UNLOCK();
366		VNET_LIST_RUNLOCK_NOSLEEP();
367		error = protosw_unregister(&send_protosw);
368		if (error == 0)
369			SEND_LOCK_DESTROY();
370		send_sendso_input_hook = NULL;
371		break;
372#endif
373	default:
374		error = 0;
375		break;
376	}
377
378	return (error);
379}
380
381static moduledata_t sendmod = {
382	"send",
383	send_modevent,
384	0
385};
386
387DECLARE_MODULE(send, sendmod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
388