subr_ipsec.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. #include "opt_inet.h"
  27. #include "opt_inet6.h"
  28. #include "opt_ipsec.h"
  29. #include <sys/cdefs.h>
  30. __FBSDID("$FreeBSD$");
  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. #include <netinet/in.h>
  44. #include <netinet/in_pcb.h>
  45. #include <netinet/ip.h>
  46. #include <netinet/ip6.h>
  47. #include <netipsec/ipsec_support.h>
  48. #include <netipsec/ipsec.h>
  49. #include <netipsec/ipsec6.h>
  50. #include <netipsec/key.h>
  51. #include <netipsec/key_debug.h>
  52. #include <netipsec/xform.h>
  53. #include <machine/atomic.h>
  54. /*
  55. * This file is build in the kernel only when 'options IPSEC' or
  56. * 'options IPSEC_SUPPORT' is enabled.
  57. */
  58. #ifdef INET
  59. void
  60. ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
  61. union sockaddr_union *dst)
  62. {
  63. static const struct sockaddr_in template = {
  64. sizeof (struct sockaddr_in),
  65. AF_INET,
  66. 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
  67. };
  68. src->sin = template;
  69. dst->sin = template;
  70. if (m->m_len < sizeof (struct ip)) {
  71. m_copydata(m, offsetof(struct ip, ip_src),
  72. sizeof (struct in_addr),
  73. (caddr_t) &src->sin.sin_addr);
  74. m_copydata(m, offsetof(struct ip, ip_dst),
  75. sizeof (struct in_addr),
  76. (caddr_t) &dst->sin.sin_addr);
  77. } else {
  78. const struct ip *ip = mtod(m, const struct ip *);
  79. src->sin.sin_addr = ip->ip_src;
  80. dst->sin.sin_addr = ip->ip_dst;
  81. }
  82. }
  83. #endif
  84. #ifdef INET6
  85. void
  86. ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
  87. union sockaddr_union *dst)
  88. {
  89. struct ip6_hdr ip6buf;
  90. const struct ip6_hdr *ip6;
  91. if (m->m_len >= sizeof(*ip6))
  92. ip6 = mtod(m, const struct ip6_hdr *);
  93. else {
  94. m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
  95. ip6 = &ip6buf;
  96. }
  97. bzero(&src->sin6, sizeof(struct sockaddr_in6));
  98. src->sin6.sin6_family = AF_INET6;
  99. src->sin6.sin6_len = sizeof(struct sockaddr_in6);
  100. bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
  101. if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
  102. src->sin6.sin6_addr.s6_addr16[1] = 0;
  103. src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
  104. }
  105. bzero(&dst->sin6, sizeof(struct sockaddr_in6));
  106. dst->sin6.sin6_family = AF_INET6;
  107. dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
  108. bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
  109. if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
  110. dst->sin6.sin6_addr.s6_addr16[1] = 0;
  111. dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
  112. }
  113. }
  114. #endif
  115. #define IPSEC_MODULE_INCR 2
  116. static int
  117. ipsec_kmod_enter(volatile u_int *cntr)
  118. {
  119. u_int old, new;
  120. do {
  121. old = *cntr;
  122. if ((old & IPSEC_MODULE_ENABLED) == 0)
  123. return (ENXIO);
  124. new = old + IPSEC_MODULE_INCR;
  125. } while(atomic_cmpset_acq_int(cntr, old, new) == 0);
  126. return (0);
  127. }
  128. static void
  129. ipsec_kmod_exit(volatile u_int *cntr)
  130. {
  131. u_int old, new;
  132. do {
  133. old = *cntr;
  134. new = old - IPSEC_MODULE_INCR;
  135. } while (atomic_cmpset_rel_int(cntr, old, new) == 0);
  136. }
  137. static void
  138. ipsec_kmod_drain(volatile u_int *cntr)
  139. {
  140. u_int old, new;
  141. do {
  142. old = *cntr;
  143. new = old & ~IPSEC_MODULE_ENABLED;
  144. } while (atomic_cmpset_acq_int(cntr, old, new) == 0);
  145. while (atomic_cmpset_int(cntr, 0, 0) == 0)
  146. pause("ipsecd", hz/2);
  147. }
  148. static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
  149. static struct mtx xforms_lock;
  150. MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
  151. #define XFORMS_LOCK() mtx_lock(&xforms_lock)
  152. #define XFORMS_UNLOCK() mtx_unlock(&xforms_lock)
  153. void
  154. xform_attach(void *data)
  155. {
  156. struct xformsw *xsp, *entry;
  157. xsp = (struct xformsw *)data;
  158. XFORMS_LOCK();
  159. LIST_FOREACH(entry, &xforms, chain) {
  160. if (entry->xf_type == xsp->xf_type) {
  161. XFORMS_UNLOCK();
  162. printf("%s: failed to register %s xform\n",
  163. __func__, xsp->xf_name);
  164. return;
  165. }
  166. }
  167. LIST_INSERT_HEAD(&xforms, xsp, chain);
  168. xsp->xf_cntr = IPSEC_MODULE_ENABLED;
  169. XFORMS_UNLOCK();
  170. }
  171. void
  172. xform_detach(void *data)
  173. {
  174. struct xformsw *xsp = (struct xformsw *)data;
  175. XFORMS_LOCK();
  176. LIST_REMOVE(xsp, chain);
  177. XFORMS_UNLOCK();
  178. /* Delete all SAs related to this xform. */
  179. key_delete_xform(xsp);
  180. if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
  181. ipsec_kmod_drain(&xsp->xf_cntr);
  182. }
  183. /*
  184. * Initialize transform support in an sav.
  185. */
  186. int
  187. xform_init(struct secasvar *sav, u_short xftype)
  188. {
  189. struct xformsw *entry;
  190. int ret;
  191. IPSEC_ASSERT(sav->tdb_xform == NULL,
  192. ("tdb_xform is already initialized"));
  193. XFORMS_LOCK();
  194. LIST_FOREACH(entry, &xforms, chain) {
  195. if (entry->xf_type == xftype) {
  196. ret = ipsec_kmod_enter(&entry->xf_cntr);
  197. XFORMS_UNLOCK();
  198. if (ret != 0)
  199. return (ret);
  200. ret = (*entry->xf_init)(sav, entry);
  201. ipsec_kmod_exit(&entry->xf_cntr);
  202. return (ret);
  203. }
  204. }
  205. XFORMS_UNLOCK();
  206. return (EINVAL);
  207. }
  208. #ifdef IPSEC_SUPPORT
  209. /*
  210. * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
  211. * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
  212. * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
  213. * IPSEC_SUPPORT.
  214. */
  215. #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
  216. #define METHOD_DECL(...) __VA_ARGS__
  217. #define METHOD_ARGS(...) __VA_ARGS__
  218. #define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args) \
  219. type name (decl) \
  220. { \
  221. type ret = (type)ipsec_kmod_enter(&sc->enabled); \
  222. if (ret == 0) { \
  223. ret = (*sc->methods->method)(args); \
  224. ipsec_kmod_exit(&sc->enabled); \
  225. } \
  226. return (ret); \
  227. }
  228. static int
  229. ipsec_support_modevent(module_t mod, int type, void *data)
  230. {
  231. switch (type) {
  232. case MOD_LOAD:
  233. return (0);
  234. case MOD_UNLOAD:
  235. return (EBUSY);
  236. default:
  237. return (EOPNOTSUPP);
  238. }
  239. }
  240. static moduledata_t ipsec_support_mod = {
  241. "ipsec_support",
  242. ipsec_support_modevent,
  243. 0
  244. };
  245. DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
  246. SI_ORDER_ANY);
  247. MODULE_VERSION(ipsec_support, 1);
  248. #endif /* !IPSEC || !TCP_SIGNATURE */
  249. #ifndef TCP_SIGNATURE
  250. /* Declare TCP-MD5 support as kernel module. */
  251. static struct tcpmd5_support tcpmd5_ipsec = {
  252. .enabled = 0,
  253. .methods = NULL
  254. };
  255. struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
  256. IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
  257. input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  258. struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  259. )
  260. IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
  261. output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  262. struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  263. )
  264. IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
  265. pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
  266. struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  267. )
  268. void
  269. tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
  270. {
  271. KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
  272. tcp_ipsec_support->methods = methods;
  273. tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
  274. }
  275. void
  276. tcpmd5_support_disable(void)
  277. {
  278. if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
  279. ipsec_kmod_drain(&tcp_ipsec_support->enabled);
  280. tcp_ipsec_support->methods = NULL;
  281. }
  282. }
  283. #endif /* !TCP_SIGNATURE */
  284. #ifndef IPSEC
  285. /*
  286. * IPsec support is build as kernel module.
  287. */
  288. #ifdef INET
  289. static struct ipsec_support ipv4_ipsec = {
  290. .enabled = 0,
  291. .methods = NULL
  292. };
  293. struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
  294. IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
  295. udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  296. int off, int af), METHOD_ARGS(m, off, af)
  297. )
  298. IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
  299. udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  300. struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  301. )
  302. #endif
  303. #ifdef INET6
  304. static struct ipsec_support ipv6_ipsec = {
  305. .enabled = 0,
  306. .methods = NULL
  307. };
  308. struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
  309. #endif
  310. IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
  311. input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  312. int offset, int proto), METHOD_ARGS(m, offset, proto)
  313. )
  314. IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
  315. check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  316. struct inpcb *inp), METHOD_ARGS(m, inp)
  317. )
  318. IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
  319. forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
  320. (m)
  321. )
  322. IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
  323. output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  324. struct inpcb *inp), METHOD_ARGS(m, inp)
  325. )
  326. IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
  327. pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  328. struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  329. )
  330. IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
  331. hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
  332. (inp)
  333. )
  334. static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
  335. capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  336. u_int cap), METHOD_ARGS(m, cap)
  337. )
  338. int
  339. ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
  340. u_int cap)
  341. {
  342. /*
  343. * Since PF_KEY is build in the kernel, we can directly
  344. * call key_havesp() without additional synchronizations.
  345. */
  346. if (cap == IPSEC_CAP_OPERABLE)
  347. return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
  348. key_havesp(IPSEC_DIR_OUTBOUND) != 0);
  349. return (ipsec_kmod_caps(sc, m, cap));
  350. }
  351. void
  352. ipsec_support_enable(struct ipsec_support * const sc,
  353. const struct ipsec_methods * const methods)
  354. {
  355. KASSERT(sc->enabled == 0, ("IPsec already enabled"));
  356. sc->methods = methods;
  357. sc->enabled |= IPSEC_MODULE_ENABLED;
  358. }
  359. void
  360. ipsec_support_disable(struct ipsec_support * const sc)
  361. {
  362. if (sc->enabled & IPSEC_MODULE_ENABLED) {
  363. ipsec_kmod_drain(&sc->enabled);
  364. sc->methods = NULL;
  365. }
  366. }
  367. #endif /* !IPSEC */
  368. #endif /* IPSEC_SUPPORT */