2 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "opt_inet6.h"
29 #include "opt_ipsec.h"
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
38 #include <sys/malloc.h>
40 #include <sys/module.h>
42 #include <sys/socket.h>
43 #include <sys/sockopt.h>
44 #include <sys/syslog.h>
47 #include <netinet/in.h>
48 #include <netinet/in_pcb.h>
49 #include <netinet/ip.h>
50 #include <netinet/ip6.h>
52 #include <netipsec/ipsec_support.h>
53 #include <netipsec/ipsec.h>
54 #include <netipsec/ipsec6.h>
55 #include <netipsec/key.h>
56 #include <netipsec/key_debug.h>
57 #include <netipsec/xform.h>
59 #include <machine/atomic.h>
61 * This file is build in the kernel only when 'options IPSEC' or
62 * 'options IPSEC_SUPPORT' is enabled.
67 ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
68 union sockaddr_union *dst)
70 static const struct sockaddr_in template = {
71 sizeof (struct sockaddr_in),
73 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
79 if (m->m_len < sizeof (struct ip)) {
80 m_copydata(m, offsetof(struct ip, ip_src),
81 sizeof (struct in_addr),
82 (caddr_t) &src->sin.sin_addr);
83 m_copydata(m, offsetof(struct ip, ip_dst),
84 sizeof (struct in_addr),
85 (caddr_t) &dst->sin.sin_addr);
87 const struct ip *ip = mtod(m, const struct ip *);
88 src->sin.sin_addr = ip->ip_src;
89 dst->sin.sin_addr = ip->ip_dst;
95 ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
96 union sockaddr_union *dst)
98 struct ip6_hdr ip6buf;
99 const struct ip6_hdr *ip6;
101 if (m->m_len >= sizeof(*ip6))
102 ip6 = mtod(m, const struct ip6_hdr *);
104 m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
108 bzero(&src->sin6, sizeof(struct sockaddr_in6));
109 src->sin6.sin6_family = AF_INET6;
110 src->sin6.sin6_len = sizeof(struct sockaddr_in6);
111 bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
112 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
113 src->sin6.sin6_addr.s6_addr16[1] = 0;
114 src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
117 bzero(&dst->sin6, sizeof(struct sockaddr_in6));
118 dst->sin6.sin6_family = AF_INET6;
119 dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
120 bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
121 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
122 dst->sin6.sin6_addr.s6_addr16[1] = 0;
123 dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
128 #define IPSEC_MODULE_INCR 2
130 ipsec_kmod_enter(volatile u_int *cntr)
136 if ((old & IPSEC_MODULE_ENABLED) == 0)
138 new = old + IPSEC_MODULE_INCR;
139 } while(atomic_cmpset_acq_int(cntr, old, new) == 0);
144 ipsec_kmod_exit(volatile u_int *cntr)
150 new = old - IPSEC_MODULE_INCR;
151 } while (atomic_cmpset_rel_int(cntr, old, new) == 0);
155 ipsec_kmod_drain(volatile u_int *cntr)
161 new = old & ~IPSEC_MODULE_ENABLED;
162 } while (atomic_cmpset_acq_int(cntr, old, new) == 0);
163 while (atomic_cmpset_int(cntr, 0, 0) == 0)
164 pause("ipsecd", hz/2);
167 static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
168 static struct mtx xforms_lock;
169 MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
170 #define XFORMS_LOCK() mtx_lock(&xforms_lock)
171 #define XFORMS_UNLOCK() mtx_unlock(&xforms_lock)
174 xform_attach(void *data)
176 struct xformsw *xsp, *entry;
178 xsp = (struct xformsw *)data;
180 LIST_FOREACH(entry, &xforms, chain) {
181 if (entry->xf_type == xsp->xf_type) {
183 printf("%s: failed to register %s xform\n",
184 __func__, xsp->xf_name);
188 LIST_INSERT_HEAD(&xforms, xsp, chain);
189 xsp->xf_cntr = IPSEC_MODULE_ENABLED;
194 xform_detach(void *data)
196 struct xformsw *xsp = (struct xformsw *)data;
199 LIST_REMOVE(xsp, chain);
202 /* Delete all SAs related to this xform. */
203 key_delete_xform(xsp);
204 if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
205 ipsec_kmod_drain(&xsp->xf_cntr);
209 * Initialize transform support in an sav.
212 xform_init(struct secasvar *sav, u_short xftype)
214 struct xformsw *entry;
217 IPSEC_ASSERT(sav->tdb_xform == NULL,
218 ("tdb_xform is already initialized"));
221 LIST_FOREACH(entry, &xforms, chain) {
222 if (entry->xf_type == xftype) {
223 ret = ipsec_kmod_enter(&entry->xf_cntr);
227 ret = (*entry->xf_init)(sav, entry);
228 ipsec_kmod_exit(&entry->xf_cntr);
238 * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
239 * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
240 * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
243 #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
244 #define METHOD_DECL(...) __VA_ARGS__
245 #define METHOD_ARGS(...) __VA_ARGS__
246 #define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args) \
249 type ret = (type)ipsec_kmod_enter(&sc->enabled); \
251 ret = (*sc->methods->method)(args); \
252 ipsec_kmod_exit(&sc->enabled); \
258 ipsec_support_modevent(module_t mod, int type, void *data)
271 static moduledata_t ipsec_support_mod = {
273 ipsec_support_modevent,
276 DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
278 MODULE_VERSION(ipsec_support, 1);
279 #endif /* !IPSEC || !TCP_SIGNATURE */
281 #ifndef TCP_SIGNATURE
282 /* Declare TCP-MD5 support as kernel module. */
283 static struct tcpmd5_support tcpmd5_ipsec = {
287 struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
289 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
290 input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
291 struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
294 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
295 output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
296 struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
299 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
300 pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
301 struct sockopt *sopt), METHOD_ARGS(inp, sopt)
305 tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
308 KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
309 tcp_ipsec_support->methods = methods;
310 tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
314 tcpmd5_support_disable(void)
317 if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
318 ipsec_kmod_drain(&tcp_ipsec_support->enabled);
319 tcp_ipsec_support->methods = NULL;
322 #endif /* !TCP_SIGNATURE */
326 * IPsec support is build as kernel module.
329 static struct ipsec_support ipv4_ipsec = {
333 struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
335 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
336 udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
337 int off, int af), METHOD_ARGS(m, off, af)
340 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
341 udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
342 struct sockopt *sopt), METHOD_ARGS(inp, sopt)
347 static struct ipsec_support ipv6_ipsec = {
351 struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
354 IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
355 input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
356 int offset, int proto), METHOD_ARGS(m, offset, proto)
359 IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
360 check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
361 struct inpcb *inp), METHOD_ARGS(m, inp)
364 IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
365 forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
369 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
370 output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
371 struct inpcb *inp), METHOD_ARGS(m, inp)
374 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
375 pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
376 struct sockopt *sopt), METHOD_ARGS(inp, sopt)
379 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
380 hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
384 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
385 capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
386 u_int cap), METHOD_ARGS(m, cap)
390 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
395 * Since PF_KEY is build in the kernel, we can directly
396 * call key_havesp() without additional synchronizations.
398 if (cap == IPSEC_CAP_OPERABLE)
399 return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
400 key_havesp(IPSEC_DIR_OUTBOUND) != 0);
401 return (ipsec_kmod_caps(sc, m, cap));
405 ipsec_support_enable(struct ipsec_support * const sc,
406 const struct ipsec_methods * const methods)
409 KASSERT(sc->enabled == 0, ("IPsec already enabled"));
410 sc->methods = methods;
411 sc->enabled |= IPSEC_MODULE_ENABLED;
415 ipsec_support_disable(struct ipsec_support * const sc)
418 if (sc->enabled & IPSEC_MODULE_ENABLED) {
419 ipsec_kmod_drain(&sc->enabled);
424 #endif /* IPSEC_SUPPORT */