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 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 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 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 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 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 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 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 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 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 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 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 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_ctlinput, sc, 368 ctlinput, METHOD_DECL(struct ipsec_support * const sc, 369 ipsec_ctlinput_param_t param), METHOD_ARGS(param) 370 ) 371 372 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc, 373 output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 374 struct inpcb *inp), METHOD_ARGS(m, inp) 375 ) 376 377 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc, 378 pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp, 379 struct sockopt *sopt), METHOD_ARGS(inp, sopt) 380 ) 381 382 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc, 383 hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp), 384 (inp) 385 ) 386 387 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc, 388 capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 389 u_int cap), METHOD_ARGS(m, cap) 390 ) 391 392 int 393 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m, 394 u_int cap) 395 { 396 397 /* 398 * Since PF_KEY is build in the kernel, we can directly 399 * call key_havesp() without additional synchronizations. 400 */ 401 if (cap == IPSEC_CAP_OPERABLE) 402 return (key_havesp_any()); 403 return (ipsec_kmod_caps(sc, m, cap)); 404 } 405 406 void 407 ipsec_support_enable(struct ipsec_support * const sc, 408 const struct ipsec_methods * const methods) 409 { 410 411 KASSERT(sc->enabled == 0, ("IPsec already enabled")); 412 sc->methods = methods; 413 sc->enabled |= IPSEC_MODULE_ENABLED; 414 } 415 416 void 417 ipsec_support_disable(struct ipsec_support * const sc) 418 { 419 420 if (sc->enabled & IPSEC_MODULE_ENABLED) { 421 ipsec_kmod_drain(&sc->enabled); 422 sc->methods = NULL; 423 } 424 } 425 #endif /* !IPSEC */ 426 #endif /* IPSEC_SUPPORT */ 427