xref: /freebsd/sys/netipsec/subr_ipsec.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "opt_inet.h"
28 #include "opt_inet6.h"
29 #include "opt_ipsec.h"
30 
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/module.h>
39 #include <sys/priv.h>
40 #include <sys/socket.h>
41 #include <sys/sockopt.h>
42 #include <sys/syslog.h>
43 #include <sys/proc.h>
44 
45 #include <netinet/in.h>
46 #include <netinet/in_pcb.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip6.h>
49 
50 #include <netipsec/ipsec_support.h>
51 #include <netipsec/ipsec.h>
52 #include <netipsec/ipsec6.h>
53 #include <netipsec/key.h>
54 #include <netipsec/key_debug.h>
55 #include <netipsec/xform.h>
56 
57 #include <machine/atomic.h>
58 /*
59  * This file is build in the kernel only when 'options IPSEC' or
60  * 'options IPSEC_SUPPORT' is enabled.
61  */
62 
63 #ifdef INET
64 void
65 ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
66     union sockaddr_union *dst)
67 {
68 	static const struct sockaddr_in template = {
69 		sizeof (struct sockaddr_in),
70 		AF_INET,
71 		0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
72 	};
73 
74 	src->sin = template;
75 	dst->sin = template;
76 
77 	if (m->m_len < sizeof (struct ip)) {
78 		m_copydata(m, offsetof(struct ip, ip_src),
79 			   sizeof (struct  in_addr),
80 			   (caddr_t) &src->sin.sin_addr);
81 		m_copydata(m, offsetof(struct ip, ip_dst),
82 			   sizeof (struct  in_addr),
83 			   (caddr_t) &dst->sin.sin_addr);
84 	} else {
85 		const struct ip *ip = mtod(m, const struct ip *);
86 		src->sin.sin_addr = ip->ip_src;
87 		dst->sin.sin_addr = ip->ip_dst;
88 	}
89 }
90 #endif
91 #ifdef INET6
92 void
93 ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
94     union sockaddr_union *dst)
95 {
96 	struct ip6_hdr ip6buf;
97 	const struct ip6_hdr *ip6;
98 
99 	if (m->m_len >= sizeof(*ip6))
100 		ip6 = mtod(m, const struct ip6_hdr *);
101 	else {
102 		m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
103 		ip6 = &ip6buf;
104 	}
105 
106 	bzero(&src->sin6, sizeof(struct sockaddr_in6));
107 	src->sin6.sin6_family = AF_INET6;
108 	src->sin6.sin6_len = sizeof(struct sockaddr_in6);
109 	bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
110 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
111 		src->sin6.sin6_addr.s6_addr16[1] = 0;
112 		src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
113 	}
114 
115 	bzero(&dst->sin6, sizeof(struct sockaddr_in6));
116 	dst->sin6.sin6_family = AF_INET6;
117 	dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
118 	bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
119 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
120 		dst->sin6.sin6_addr.s6_addr16[1] = 0;
121 		dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
122 	}
123 }
124 #endif
125 
126 #define	IPSEC_MODULE_INCR	2
127 static int
128 ipsec_kmod_enter(volatile u_int *cntr)
129 {
130 	u_int old, new;
131 
132 	do {
133 		old = *cntr;
134 		if ((old & IPSEC_MODULE_ENABLED) == 0)
135 			return (ENXIO);
136 		new = old + IPSEC_MODULE_INCR;
137 	} while(atomic_cmpset_acq_int(cntr, old, new) == 0);
138 	return (0);
139 }
140 
141 static void
142 ipsec_kmod_exit(volatile u_int *cntr)
143 {
144 	u_int old, new;
145 
146 	do {
147 		old = *cntr;
148 		new = old - IPSEC_MODULE_INCR;
149 	} while (atomic_cmpset_rel_int(cntr, old, new) == 0);
150 }
151 
152 static void
153 ipsec_kmod_drain(volatile u_int *cntr)
154 {
155 	u_int old, new;
156 
157 	do {
158 		old = *cntr;
159 		new = old & ~IPSEC_MODULE_ENABLED;
160 	} while (atomic_cmpset_acq_int(cntr, old, new) == 0);
161 	while (atomic_cmpset_int(cntr, 0, 0) == 0)
162 		pause("ipsecd", hz/2);
163 }
164 
165 static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
166 static struct mtx xforms_lock;
167 MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
168 #define	XFORMS_LOCK()		mtx_lock(&xforms_lock)
169 #define	XFORMS_UNLOCK()		mtx_unlock(&xforms_lock)
170 
171 void
172 xform_attach(void *data)
173 {
174 	struct xformsw *xsp, *entry;
175 
176 	xsp = (struct xformsw *)data;
177 	XFORMS_LOCK();
178 	LIST_FOREACH(entry, &xforms, chain) {
179 		if (entry->xf_type == xsp->xf_type) {
180 			XFORMS_UNLOCK();
181 			printf("%s: failed to register %s xform\n",
182 			    __func__, xsp->xf_name);
183 			return;
184 		}
185 	}
186 	LIST_INSERT_HEAD(&xforms, xsp, chain);
187 	xsp->xf_cntr = IPSEC_MODULE_ENABLED;
188 	XFORMS_UNLOCK();
189 }
190 
191 void
192 xform_detach(void *data)
193 {
194 	struct xformsw *xsp = (struct xformsw *)data;
195 
196 	XFORMS_LOCK();
197 	LIST_REMOVE(xsp, chain);
198 	XFORMS_UNLOCK();
199 
200 	/* Delete all SAs related to this xform. */
201 	key_delete_xform(xsp);
202 	if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
203 		ipsec_kmod_drain(&xsp->xf_cntr);
204 }
205 
206 /*
207  * Initialize transform support in an sav.
208  */
209 int
210 xform_init(struct secasvar *sav, u_short xftype)
211 {
212 	struct xformsw *entry;
213 	int ret;
214 
215 	IPSEC_ASSERT(sav->tdb_xform == NULL,
216 	    ("tdb_xform is already initialized"));
217 
218 	XFORMS_LOCK();
219 	LIST_FOREACH(entry, &xforms, chain) {
220 		if (entry->xf_type == xftype) {
221 			ret = ipsec_kmod_enter(&entry->xf_cntr);
222 			XFORMS_UNLOCK();
223 			if (ret != 0)
224 				return (ret);
225 			ret = (*entry->xf_init)(sav, entry);
226 			ipsec_kmod_exit(&entry->xf_cntr);
227 			return (ret);
228 		}
229 	}
230 	XFORMS_UNLOCK();
231 	return (EINVAL);
232 }
233 
234 #ifdef IPSEC_SUPPORT
235 /*
236  * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
237  * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
238  * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
239  *   IPSEC_SUPPORT.
240  */
241 #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
242 #define	METHOD_DECL(...)	__VA_ARGS__
243 #define	METHOD_ARGS(...)	__VA_ARGS__
244 #define	IPSEC_KMOD_METHOD(type, name, sc, method, decl, args)		\
245 type name (decl)							\
246 {									\
247 	type ret = (type)ipsec_kmod_enter(&sc->enabled);		\
248 	if (ret == 0) {							\
249 		ret = (*sc->methods->method)(args);			\
250 		ipsec_kmod_exit(&sc->enabled);				\
251 	}								\
252 	return (ret);							\
253 }
254 
255 static int
256 ipsec_support_modevent(module_t mod, int type, void *data)
257 {
258 
259 	switch (type) {
260 	case MOD_LOAD:
261 		return (0);
262 	case MOD_UNLOAD:
263 		return (EBUSY);
264 	default:
265 		return (EOPNOTSUPP);
266 	}
267 }
268 
269 static moduledata_t ipsec_support_mod = {
270 	"ipsec_support",
271 	ipsec_support_modevent,
272 	0
273 };
274 DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
275     SI_ORDER_ANY);
276 MODULE_VERSION(ipsec_support, 1);
277 #endif /* !IPSEC || !TCP_SIGNATURE */
278 
279 #ifndef TCP_SIGNATURE
280 /* Declare TCP-MD5 support as kernel module. */
281 static struct tcpmd5_support tcpmd5_ipsec = {
282 	.enabled = 0,
283 	.methods = NULL
284 };
285 struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
286 
287 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
288     input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
289 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
290 )
291 
292 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
293     output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
294 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
295 )
296 
297 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
298     pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
299 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
300 )
301 
302 void
303 tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
304 {
305 
306 	KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
307 	tcp_ipsec_support->methods = methods;
308 	tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
309 }
310 
311 void
312 tcpmd5_support_disable(void)
313 {
314 
315 	if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
316 		ipsec_kmod_drain(&tcp_ipsec_support->enabled);
317 		tcp_ipsec_support->methods = NULL;
318 	}
319 }
320 #endif /* !TCP_SIGNATURE */
321 
322 #ifndef IPSEC
323 /*
324  * IPsec support is build as kernel module.
325  */
326 #ifdef INET
327 static struct ipsec_support ipv4_ipsec = {
328 	.enabled = 0,
329 	.methods = NULL
330 };
331 struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
332 
333 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
334     udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
335 	int off, int af), METHOD_ARGS(m, off, af)
336 )
337 
338 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
339     udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
340 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
341 )
342 #endif
343 
344 #ifdef INET6
345 static struct ipsec_support ipv6_ipsec = {
346 	.enabled = 0,
347 	.methods = NULL
348 };
349 struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
350 #endif
351 
352 IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
353     input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
354 	int offset, int proto), METHOD_ARGS(m, offset, proto)
355 )
356 
357 IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
358     check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
359 	struct inpcb *inp), METHOD_ARGS(m, inp)
360 )
361 
362 IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
363     forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
364     (m)
365 )
366 
367 IPSEC_KMOD_METHOD(int, ipsec_kmod_ctlinput, sc,
368     ctlinput, METHOD_DECL(struct ipsec_support * const sc,
369 	ipsec_ctlinput_param_t param), METHOD_ARGS(param)
370 )
371 
372 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
373     output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
374 	struct inpcb *inp), METHOD_ARGS(m, inp)
375 )
376 
377 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
378     pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
379 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
380 )
381 
382 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
383     hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
384     (inp)
385 )
386 
387 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
388     capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
389 	u_int cap), METHOD_ARGS(m, cap)
390 )
391 
392 int
393 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
394     u_int cap)
395 {
396 
397 	/*
398 	 * Since PF_KEY is build in the kernel, we can directly
399 	 * call key_havesp() without additional synchronizations.
400 	 */
401 	if (cap == IPSEC_CAP_OPERABLE)
402 		return (key_havesp_any());
403 	return (ipsec_kmod_caps(sc, m, cap));
404 }
405 
406 void
407 ipsec_support_enable(struct ipsec_support * const sc,
408     const struct ipsec_methods * const methods)
409 {
410 
411 	KASSERT(sc->enabled == 0, ("IPsec already enabled"));
412 	sc->methods = methods;
413 	sc->enabled |= IPSEC_MODULE_ENABLED;
414 }
415 
416 void
417 ipsec_support_disable(struct ipsec_support * const sc)
418 {
419 
420 	if (sc->enabled & IPSEC_MODULE_ENABLED) {
421 		ipsec_kmod_drain(&sc->enabled);
422 		sc->methods = NULL;
423 	}
424 }
425 #endif /* !IPSEC */
426 #endif /* IPSEC_SUPPORT */
427