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 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 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 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 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 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 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 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 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 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 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 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 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 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 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