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 66void 67ipsec4_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 94void 95ipsec6_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 129static int 130ipsec_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 143static void 144ipsec_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 154static void 155ipsec_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 167static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER(); 168static struct mtx xforms_lock; 169MTX_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 173void 174xform_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 193void 194xform_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 */ 211int 212xform_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) \ 247type 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 257static int 258ipsec_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 271static moduledata_t ipsec_support_mod = { 272 "ipsec_support", 273 ipsec_support_modevent, 274 0 275}; 276DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN, 277 SI_ORDER_ANY); 278MODULE_VERSION(ipsec_support, 1); 279#endif /* !IPSEC || !TCP_SIGNATURE */ 280 281#ifndef TCP_SIGNATURE 282/* Declare TCP-MD5 support as kernel module. */ 283static struct tcpmd5_support tcpmd5_ipsec = { 284 .enabled = 0, 285 .methods = NULL 286}; 287struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec; 288 289IPSEC_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 294IPSEC_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 299IPSEC_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 304void 305tcpmd5_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 313void 314tcpmd5_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 329static struct ipsec_support ipv4_ipsec = { 330 .enabled = 0, 331 .methods = NULL 332}; 333struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec; 334 335IPSEC_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 340IPSEC_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 347static struct ipsec_support ipv6_ipsec = { 348 .enabled = 0, 349 .methods = NULL 350}; 351struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec; 352#endif 353 354IPSEC_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 359IPSEC_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 364IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc, 365 forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m), 366 (m) 367) 368 369IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc, 370 output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 371 struct inpcb *inp), METHOD_ARGS(m, inp) 372) 373 374IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc, 375 pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp, 376 struct sockopt *sopt), METHOD_ARGS(inp, sopt) 377) 378 379IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc, 380 hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp), 381 (inp) 382) 383 384static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc, 385 capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m, 386 u_int cap), METHOD_ARGS(m, cap) 387) 388 389int 390ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m, 391 u_int cap) 392{ 393 394 /* 395 * Since PF_KEY is build in the kernel, we can directly 396 * call key_havesp() without additional synchronizations. 397 */ 398 if (cap == IPSEC_CAP_OPERABLE) 399 return (key_havesp(IPSEC_DIR_INBOUND) != 0 || 400 key_havesp(IPSEC_DIR_OUTBOUND) != 0); 401 return (ipsec_kmod_caps(sc, m, cap)); 402} 403 404void 405ipsec_support_enable(struct ipsec_support * const sc, 406 const struct ipsec_methods * const methods) 407{ 408 409 KASSERT(sc->enabled == 0, ("IPsec already enabled")); 410 sc->methods = methods; 411 sc->enabled |= IPSEC_MODULE_ENABLED; 412} 413 414void 415ipsec_support_disable(struct ipsec_support * const sc) 416{ 417 418 if (sc->enabled & IPSEC_MODULE_ENABLED) { 419 ipsec_kmod_drain(&sc->enabled); 420 sc->methods = NULL; 421 } 422} 423#endif /* !IPSEC */ 424#endif /* IPSEC_SUPPORT */ 425