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