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
ipsec4_setsockaddrs(const struct mbuf * m,union sockaddr_union * src,union sockaddr_union * dst)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
ipsec6_setsockaddrs(const struct mbuf * m,union sockaddr_union * src,union sockaddr_union * dst)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
ipsec_kmod_enter(volatile u_int * cntr)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
ipsec_kmod_exit(volatile u_int * cntr)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
ipsec_kmod_drain(volatile u_int * cntr)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
xform_attach(void * data)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
xform_detach(void * data)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
xform_init(struct secasvar * sav,u_short xftype)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
ipsec_support_modevent(module_t mod,int type,void * data)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
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))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
tcpmd5_support_disable(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
IPSEC_KMOD_METHOD(int,ipsec_kmod_input,sc,input,METHOD_DECL (struct ipsec_support * const sc,struct mbuf * m,int offset,int proto),METHOD_ARGS (m,offset,proto))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_output, sc,
368 output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
369 struct inpcb *inp), METHOD_ARGS(m, inp)
370 )
371
372 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
373 pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
374 struct sockopt *sopt), METHOD_ARGS(inp, sopt)
375 )
376
377 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
378 hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
379 (inp)
380 )
381
382 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
383 capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
384 u_int cap), METHOD_ARGS(m, cap)
385 )
386
387 int
388 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
389 u_int cap)
390 {
391
392 /*
393 * Since PF_KEY is build in the kernel, we can directly
394 * call key_havesp() without additional synchronizations.
395 */
396 if (cap == IPSEC_CAP_OPERABLE)
397 return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
398 key_havesp(IPSEC_DIR_OUTBOUND) != 0);
399 return (ipsec_kmod_caps(sc, m, cap));
400 }
401
402 void
ipsec_support_enable(struct ipsec_support * const sc,const struct ipsec_methods * const methods)403 ipsec_support_enable(struct ipsec_support * const sc,
404 const struct ipsec_methods * const methods)
405 {
406
407 KASSERT(sc->enabled == 0, ("IPsec already enabled"));
408 sc->methods = methods;
409 sc->enabled |= IPSEC_MODULE_ENABLED;
410 }
411
412 void
ipsec_support_disable(struct ipsec_support * const sc)413 ipsec_support_disable(struct ipsec_support * const sc)
414 {
415
416 if (sc->enabled & IPSEC_MODULE_ENABLED) {
417 ipsec_kmod_drain(&sc->enabled);
418 sc->methods = NULL;
419 }
420 }
421 #endif /* !IPSEC */
422 #endif /* IPSEC_SUPPORT */
423