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 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/module.h> 41 #include <sys/priv.h> 42 #include <sys/socket.h> 43 #include <sys/sockopt.h> 44 #include <sys/syslog.h> 45 #include <sys/proc.h> 46 47 #include <netinet/in.h> 48 #include <netinet/in_pcb.h> 49 #include <netinet/ip.h> 50 #include <netinet/ip6.h> 51 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> 58 59 #include <machine/atomic.h> 60 /* 61 * This file is build in the kernel only when 'options IPSEC' or 62 * 'options IPSEC_SUPPORT' is enabled. 63 */ 64 65 #ifdef INET 66 void 67 ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src, 68 union sockaddr_union *dst) 69 { 70 static const struct sockaddr_in template = { 71 sizeof (struct sockaddr_in), 72 AF_INET, 73 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } 74 }; 75 76 src->sin = template; 77 dst->sin = template; 78 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); 86 } else { 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; 90 } 91 } 92 #endif 93 #ifdef INET6 94 void 95 ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src, 96 union sockaddr_union *dst) 97 { 98 struct ip6_hdr ip6buf; 99 const struct ip6_hdr *ip6; 100 101 if (m->m_len >= sizeof(*ip6)) 102 ip6 = mtod(m, const struct ip6_hdr *); 103 else { 104 m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); 105 ip6 = &ip6buf; 106 } 107 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]); 115 } 116 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]); 124 } 125 } 126 #endif 127 128 #define IPSEC_MODULE_INCR 2 129 static int 130 ipsec_kmod_enter(volatile u_int *cntr) 131 { 132 u_int old, new; 133 134 do { 135 old = *cntr; 136 if ((old & IPSEC_MODULE_ENABLED) == 0) 137 return (ENXIO); 138 new = old + IPSEC_MODULE_INCR; 139 } while(atomic_cmpset_acq_int(cntr, old, new) == 0); 140 return (0); 141 } 142 143 static void 144 ipsec_kmod_exit(volatile u_int *cntr) 145 { 146 u_int old, new; 147 148 do { 149 old = *cntr; 150 new = old - IPSEC_MODULE_INCR; 151 } while (atomic_cmpset_rel_int(cntr, old, new) == 0); 152 } 153 154 static void 155 ipsec_kmod_drain(volatile u_int *cntr) 156 { 157 u_int old, new; 158 159 do { 160 old = *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); 165 } 166 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) 172 173 void 174 xform_attach(void *data) 175 { 176 struct xformsw *xsp, *entry; 177 178 xsp = (struct xformsw *)data; 179 XFORMS_LOCK(); 180 LIST_FOREACH(entry, &xforms, chain) { 181 if (entry->xf_type == xsp->xf_type) { 182 XFORMS_UNLOCK(); 183 printf("%s: failed to register %s xform\n", 184 __func__, xsp->xf_name); 185 return; 186 } 187 } 188 LIST_INSERT_HEAD(&xforms, xsp, chain); 189 xsp->xf_cntr = IPSEC_MODULE_ENABLED; 190 XFORMS_UNLOCK(); 191 } 192 193 void 194 xform_detach(void *data) 195 { 196 struct xformsw *xsp = (struct xformsw *)data; 197 198 XFORMS_LOCK(); 199 LIST_REMOVE(xsp, chain); 200 XFORMS_UNLOCK(); 201 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); 206 } 207 208 /* 209 * Initialize transform support in an sav. 210 */ 211 int 212 xform_init(struct secasvar *sav, u_short xftype) 213 { 214 struct xformsw *entry; 215 int ret; 216 217 IPSEC_ASSERT(sav->tdb_xform == NULL, 218 ("tdb_xform is already initialized")); 219 220 XFORMS_LOCK(); 221 LIST_FOREACH(entry, &xforms, chain) { 222 if (entry->xf_type == xftype) { 223 ret = ipsec_kmod_enter(&entry->xf_cntr); 224 XFORMS_UNLOCK(); 225 if (ret != 0) 226 return (ret); 227 ret = (*entry->xf_init)(sav, entry); 228 ipsec_kmod_exit(&entry->xf_cntr); 229 return (ret); 230 } 231 } 232 XFORMS_UNLOCK(); 233 return (EINVAL); 234 } 235 236 #ifdef IPSEC_SUPPORT 237 /* 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 241 * IPSEC_SUPPORT. 242 */ 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) \ 247 type name (decl) \ 248 { \ 249 type ret = (type)ipsec_kmod_enter(&sc->enabled); \ 250 if (ret == 0) { \ 251 ret = (*sc->methods->method)(args); \ 252 ipsec_kmod_exit(&sc->enabled); \ 253 } \ 254 return (ret); \ 255 } 256 257 static int 258 ipsec_support_modevent(module_t mod, int type, void *data) 259 { 260 261 switch (type) { 262 case MOD_LOAD: 263 return (0); 264 case MOD_UNLOAD: 265 return (EBUSY); 266 default: 267 return (EOPNOTSUPP); 268 } 269 } 270 271 static moduledata_t ipsec_support_mod = { 272 "ipsec_support", 273 ipsec_support_modevent, 274 0 275 }; 276 DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN, 277 SI_ORDER_ANY); 278 MODULE_VERSION(ipsec_support, 1); 279 #endif /* !IPSEC || !TCP_SIGNATURE */ 280 281 #ifndef TCP_SIGNATURE 282 /* Declare TCP-MD5 support as kernel module. */ 283 static struct tcpmd5_support tcpmd5_ipsec = { 284 .enabled = 0, 285 .methods = NULL 286 }; 287 struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec; 288 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) 292 ) 293 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) 297 ) 298 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) 302 ) 303 304 void 305 tcpmd5_support_enable(const struct tcpmd5_methods * const methods) 306 { 307 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; 311 } 312 313 void 314 tcpmd5_support_disable(void) 315 { 316 317 if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) { 318 ipsec_kmod_drain(&tcp_ipsec_support->enabled); 319 tcp_ipsec_support->methods = NULL; 320 } 321 } 322 #endif /* !TCP_SIGNATURE */ 323 324 #ifndef IPSEC 325 /* 326 * IPsec support is build as kernel module. 327 */ 328 #ifdef INET 329 static struct ipsec_support ipv4_ipsec = { 330 .enabled = 0, 331 .methods = NULL 332 }; 333 struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec; 334 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) 338 ) 339 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) 343 ) 344 #endif 345 346 #ifdef INET6 347 static struct ipsec_support ipv6_ipsec = { 348 .enabled = 0, 349 .methods = NULL 350 }; 351 struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec; 352 #endif 353 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) 357 ) 358 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) 362 ) 363 364 IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc, 365 forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m), 366 (m) 367 ) 368 369 IPSEC_KMOD_METHOD(int, ipsec_kmod_ctlinput, sc, 370 ctlinput, METHOD_DECL(struct ipsec_support * const sc, 371 ipsec_ctlinput_param_t param), METHOD_ARGS(param) 372 ) 373 374 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc, 375 output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 376 struct inpcb *inp), METHOD_ARGS(m, inp) 377 ) 378 379 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc, 380 pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp, 381 struct sockopt *sopt), METHOD_ARGS(inp, sopt) 382 ) 383 384 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc, 385 hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp), 386 (inp) 387 ) 388 389 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc, 390 capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 391 u_int cap), METHOD_ARGS(m, cap) 392 ) 393 394 int 395 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m, 396 u_int cap) 397 { 398 399 /* 400 * Since PF_KEY is build in the kernel, we can directly 401 * call key_havesp() without additional synchronizations. 402 */ 403 if (cap == IPSEC_CAP_OPERABLE) 404 return (key_havesp_any()); 405 return (ipsec_kmod_caps(sc, m, cap)); 406 } 407 408 void 409 ipsec_support_enable(struct ipsec_support * const sc, 410 const struct ipsec_methods * const methods) 411 { 412 413 KASSERT(sc->enabled == 0, ("IPsec already enabled")); 414 sc->methods = methods; 415 sc->enabled |= IPSEC_MODULE_ENABLED; 416 } 417 418 void 419 ipsec_support_disable(struct ipsec_support * const sc) 420 { 421 422 if (sc->enabled & IPSEC_MODULE_ENABLED) { 423 ipsec_kmod_drain(&sc->enabled); 424 sc->methods = NULL; 425 } 426 } 427 #endif /* !IPSEC */ 428 #endif /* IPSEC_SUPPORT */ 429