1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 The FreeBSD Project. 5 * Copyright (c) 2015 Andrey V. Elsukov <ae@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 #include "opt_inet.h" 34 #include "opt_inet6.h" 35 #include "opt_ipsec.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/hhook.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/mbuf.h> 43 #include <sys/module.h> 44 #include <machine/bus.h> 45 #include <sys/rman.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/sysctl.h> 49 50 #include <net/if.h> 51 #include <net/if_enc.h> 52 #include <net/if_var.h> 53 #include <net/if_private.h> 54 #include <net/if_clone.h> 55 #include <net/if_types.h> 56 #include <net/pfil.h> 57 #include <net/route.h> 58 #include <net/netisr.h> 59 #include <net/bpf.h> 60 #include <net/vnet.h> 61 62 #include <netinet/in.h> 63 #include <netinet/in_systm.h> 64 #include <netinet/ip.h> 65 #include <netinet/ip_var.h> 66 #include <netinet/in_var.h> 67 68 #ifdef INET6 69 #include <netinet/ip6.h> 70 #include <netinet6/ip6_var.h> 71 #endif 72 73 #include <netipsec/ipsec.h> 74 #include <netipsec/xform.h> 75 76 #define ENCMTU (1024+512) 77 78 /* XXX this define must have the same value as in OpenBSD */ 79 #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 80 #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 81 #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 82 83 struct enchdr { 84 u_int32_t af; 85 u_int32_t spi; 86 u_int32_t flags; 87 }; 88 struct enc_softc { 89 struct ifnet *sc_ifp; 90 }; 91 VNET_DEFINE_STATIC(struct enc_softc *, enc_sc); 92 #define V_enc_sc VNET(enc_sc) 93 VNET_DEFINE_STATIC(struct if_clone *, enc_cloner); 94 #define V_enc_cloner VNET(enc_cloner) 95 96 static int enc_ioctl(struct ifnet *, u_long, caddr_t); 97 static int enc_output(struct ifnet *, struct mbuf *, 98 const struct sockaddr *, struct route *); 99 static int enc_clone_create(struct if_clone *, int, caddr_t); 100 static void enc_clone_destroy(struct ifnet *); 101 static int enc_add_hhooks(struct enc_softc *); 102 static void enc_remove_hhooks(struct enc_softc *); 103 104 static const char encname[] = "enc"; 105 106 #define IPSEC_ENC_AFTER_PFIL 0x04 107 /* 108 * Before and after are relative to when we are stripping the 109 * outer IP header. 110 * 111 * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing 112 * after PFIL hook execution. It might be useful when PFIL hook does 113 * some changes to the packet, e.g. address translation. If PFIL hook 114 * consumes mbuf, nothing will be captured. 115 */ 116 VNET_DEFINE_STATIC(int, filter_mask_in) = IPSEC_ENC_BEFORE; 117 VNET_DEFINE_STATIC(int, bpf_mask_in) = IPSEC_ENC_BEFORE; 118 VNET_DEFINE_STATIC(int, filter_mask_out) = IPSEC_ENC_BEFORE; 119 VNET_DEFINE_STATIC(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER; 120 #define V_filter_mask_in VNET(filter_mask_in) 121 #define V_bpf_mask_in VNET(bpf_mask_in) 122 #define V_filter_mask_out VNET(filter_mask_out) 123 #define V_bpf_mask_out VNET(bpf_mask_out) 124 125 static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 126 "enc sysctl"); 127 static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 128 "enc input sysctl"); 129 static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 130 "enc output sysctl"); 131 SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, 132 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0, 133 "IPsec input firewall filter mask"); 134 SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, 135 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0, 136 "IPsec input bpf mask"); 137 SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, 138 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0, 139 "IPsec output firewall filter mask"); 140 SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, 141 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0, 142 "IPsec output bpf mask"); 143 144 static void 145 enc_clone_destroy(struct ifnet *ifp) 146 { 147 struct enc_softc *sc; 148 149 sc = ifp->if_softc; 150 KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc")); 151 152 bpfdetach(ifp); 153 if_detach(ifp); 154 if_free(ifp); 155 free(sc, M_DEVBUF); 156 V_enc_sc = NULL; 157 } 158 159 static int 160 enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 161 { 162 struct ifnet *ifp; 163 struct enc_softc *sc; 164 165 sc = malloc(sizeof(struct enc_softc), M_DEVBUF, 166 M_WAITOK | M_ZERO); 167 ifp = sc->sc_ifp = if_alloc(IFT_ENC); 168 if (ifp == NULL) { 169 free(sc, M_DEVBUF); 170 return (ENOSPC); 171 } 172 if (V_enc_sc != NULL) { 173 if_free(ifp); 174 free(sc, M_DEVBUF); 175 return (EEXIST); 176 } 177 V_enc_sc = sc; 178 if_initname(ifp, encname, unit); 179 ifp->if_mtu = ENCMTU; 180 ifp->if_ioctl = enc_ioctl; 181 ifp->if_output = enc_output; 182 ifp->if_softc = sc; 183 if_attach(ifp); 184 bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 185 return (0); 186 } 187 188 static int 189 enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 190 struct route *ro) 191 { 192 193 m_freem(m); 194 return (0); 195 } 196 197 static int 198 enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 199 { 200 201 if (cmd != SIOCSIFFLAGS) 202 return (EINVAL); 203 if (ifp->if_flags & IFF_UP) 204 ifp->if_drv_flags |= IFF_DRV_RUNNING; 205 else 206 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 207 return (0); 208 } 209 210 static void 211 enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, 212 int32_t hhook_type, uint8_t enc, uint8_t af) 213 { 214 struct enchdr hdr; 215 216 if (hhook_type == HHOOK_TYPE_IPSEC_IN && 217 (enc & V_bpf_mask_in) == 0) 218 return; 219 else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && 220 (enc & V_bpf_mask_out) == 0) 221 return; 222 if (bpf_peers_present(ifp->if_bpf) == 0) 223 return; 224 hdr.af = af; 225 hdr.spi = sav->spi; 226 hdr.flags = 0; 227 if (sav->alg_enc != SADB_EALG_NONE) 228 hdr.flags |= M_CONF; 229 if (sav->alg_auth != SADB_AALG_NONE) 230 hdr.flags |= M_AUTH; 231 bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); 232 } 233 234 /* 235 * One helper hook function is used by any hook points. 236 * + from hhook_type we can determine the packet direction: 237 * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT; 238 * + from hhook_id we can determine address family: AF_INET or AF_INET6; 239 * + udata contains pointer to enc_softc; 240 * + ctx_data contains pointer to struct ipsec_ctx_data. 241 */ 242 static int 243 enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, 244 void *hdata, struct osd *hosd) 245 { 246 struct ipsec_ctx_data *ctx; 247 struct enc_softc *sc; 248 struct ifnet *ifp, *rcvif; 249 struct pfil_head *ph; 250 int pdir; 251 252 sc = (struct enc_softc *)udata; 253 ifp = sc->sc_ifp; 254 if ((ifp->if_flags & IFF_UP) == 0) 255 return (0); 256 257 ctx = (struct ipsec_ctx_data *)ctx_data; 258 /* XXX: wrong hook point was used by caller? */ 259 if (ctx->af != hhook_id) 260 return (EPFNOSUPPORT); 261 262 enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); 263 switch (hhook_type) { 264 case HHOOK_TYPE_IPSEC_IN: 265 if (ctx->enc == IPSEC_ENC_BEFORE) { 266 /* Do accounting only once */ 267 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 268 if_inc_counter(ifp, IFCOUNTER_IBYTES, 269 (*ctx->mp)->m_pkthdr.len); 270 } 271 if ((ctx->enc & V_filter_mask_in) == 0) 272 return (0); /* skip pfil processing */ 273 pdir = PFIL_IN; 274 break; 275 case HHOOK_TYPE_IPSEC_OUT: 276 if (ctx->enc == IPSEC_ENC_BEFORE) { 277 /* Do accounting only once */ 278 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 279 if_inc_counter(ifp, IFCOUNTER_OBYTES, 280 (*ctx->mp)->m_pkthdr.len); 281 } 282 if ((ctx->enc & V_filter_mask_out) == 0) 283 return (0); /* skip pfil processing */ 284 pdir = PFIL_OUT; 285 break; 286 default: 287 return (EINVAL); 288 } 289 290 switch (hhook_id) { 291 #ifdef INET 292 case AF_INET: 293 ph = V_inet_pfil_head; 294 break; 295 #endif 296 #ifdef INET6 297 case AF_INET6: 298 ph = V_inet6_pfil_head; 299 break; 300 #endif 301 default: 302 ph = NULL; 303 } 304 if (ph == NULL || (pdir == PFIL_OUT && !PFIL_HOOKED_OUT(ph)) || 305 (pdir == PFIL_IN && !PFIL_HOOKED_IN(ph))) 306 return (0); 307 /* Make a packet looks like it was received on enc(4) */ 308 rcvif = (*ctx->mp)->m_pkthdr.rcvif; 309 (*ctx->mp)->m_pkthdr.rcvif = ifp; 310 if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != PFIL_PASS) { 311 *ctx->mp = NULL; /* consumed by filter */ 312 return (EACCES); 313 } 314 (*ctx->mp)->m_pkthdr.rcvif = rcvif; 315 enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, 316 IPSEC_ENC_AFTER_PFIL, ctx->af); 317 return (0); 318 } 319 320 static int 321 enc_add_hhooks(struct enc_softc *sc) 322 { 323 struct hookinfo hki; 324 int error; 325 326 error = EPFNOSUPPORT; 327 hki.hook_func = enc_hhook; 328 hki.hook_helper = NULL; 329 hki.hook_udata = sc; 330 #ifdef INET 331 hki.hook_id = AF_INET; 332 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 333 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 334 &hki, HHOOK_WAITOK); 335 if (error != 0) 336 return (error); 337 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 338 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 339 &hki, HHOOK_WAITOK); 340 if (error != 0) 341 return (error); 342 #endif 343 #ifdef INET6 344 hki.hook_id = AF_INET6; 345 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 346 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 347 &hki, HHOOK_WAITOK); 348 if (error != 0) 349 return (error); 350 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 351 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 352 &hki, HHOOK_WAITOK); 353 if (error != 0) 354 return (error); 355 #endif 356 return (error); 357 } 358 359 static void 360 enc_remove_hhooks(struct enc_softc *sc) 361 { 362 struct hookinfo hki; 363 364 hki.hook_func = enc_hhook; 365 hki.hook_helper = NULL; 366 hki.hook_udata = sc; 367 #ifdef INET 368 hki.hook_id = AF_INET; 369 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 370 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 371 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 372 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 373 #endif 374 #ifdef INET6 375 hki.hook_id = AF_INET6; 376 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 377 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 378 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 379 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 380 #endif 381 } 382 383 static void 384 vnet_enc_init(const void *unused __unused) 385 { 386 387 V_enc_sc = NULL; 388 V_enc_cloner = if_clone_simple(encname, enc_clone_create, 389 enc_clone_destroy, 1); 390 } 391 VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 392 vnet_enc_init, NULL); 393 394 static void 395 vnet_enc_init_proto(void *unused __unused) 396 { 397 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 398 399 if (enc_add_hhooks(V_enc_sc) != 0) 400 enc_clone_destroy(V_enc_sc->sc_ifp); 401 } 402 VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 403 vnet_enc_init_proto, NULL); 404 405 static void 406 vnet_enc_uninit(const void *unused __unused) 407 { 408 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 409 410 if_clone_detach(V_enc_cloner); 411 } 412 VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 413 vnet_enc_uninit, NULL); 414 415 /* 416 * The hhook consumer needs to go before ip[6]_destroy are called on 417 * SI_ORDER_THIRD. 418 */ 419 static void 420 vnet_enc_uninit_hhook(const void *unused __unused) 421 { 422 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 423 424 enc_remove_hhooks(V_enc_sc); 425 } 426 VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 427 vnet_enc_uninit_hhook, NULL); 428 429 static int 430 enc_modevent(module_t mod, int type, void *data) 431 { 432 433 switch (type) { 434 case MOD_LOAD: 435 case MOD_UNLOAD: 436 break; 437 default: 438 return (EOPNOTSUPP); 439 } 440 return (0); 441 } 442 443 static moduledata_t enc_mod = { 444 "if_enc", 445 enc_modevent, 446 0 447 }; 448 449 DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 450 MODULE_VERSION(if_enc, 1); 451