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_clone.h> 54 #include <net/if_types.h> 55 #include <net/pfil.h> 56 #include <net/route.h> 57 #include <net/netisr.h> 58 #include <net/bpf.h> 59 #include <net/vnet.h> 60 61 #include <netinet/in.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/ip.h> 64 #include <netinet/ip_var.h> 65 #include <netinet/in_var.h> 66 67 #ifdef INET6 68 #include <netinet/ip6.h> 69 #include <netinet6/ip6_var.h> 70 #endif 71 72 #include <netipsec/ipsec.h> 73 #include <netipsec/xform.h> 74 75 #define ENCMTU (1024+512) 76 77 /* XXX this define must have the same value as in OpenBSD */ 78 #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 79 #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 80 #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 81 82 struct enchdr { 83 u_int32_t af; 84 u_int32_t spi; 85 u_int32_t flags; 86 }; 87 struct enc_softc { 88 struct ifnet *sc_ifp; 89 }; 90 VNET_DEFINE_STATIC(struct enc_softc *, enc_sc); 91 #define V_enc_sc VNET(enc_sc) 92 VNET_DEFINE_STATIC(struct if_clone *, enc_cloner); 93 #define V_enc_cloner VNET(enc_cloner) 94 95 static int enc_ioctl(struct ifnet *, u_long, caddr_t); 96 static int enc_output(struct ifnet *, struct mbuf *, 97 const struct sockaddr *, struct route *); 98 static int enc_clone_create(struct if_clone *, int, caddr_t); 99 static void enc_clone_destroy(struct ifnet *); 100 static int enc_add_hhooks(struct enc_softc *); 101 static void enc_remove_hhooks(struct enc_softc *); 102 103 static const char encname[] = "enc"; 104 105 #define IPSEC_ENC_AFTER_PFIL 0x04 106 /* 107 * Before and after are relative to when we are stripping the 108 * outer IP header. 109 * 110 * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing 111 * after PFIL hook execution. It might be useful when PFIL hook does 112 * some changes to the packet, e.g. address translation. If PFIL hook 113 * consumes mbuf, nothing will be captured. 114 */ 115 VNET_DEFINE_STATIC(int, filter_mask_in) = IPSEC_ENC_BEFORE; 116 VNET_DEFINE_STATIC(int, bpf_mask_in) = IPSEC_ENC_BEFORE; 117 VNET_DEFINE_STATIC(int, filter_mask_out) = IPSEC_ENC_BEFORE; 118 VNET_DEFINE_STATIC(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER; 119 #define V_filter_mask_in VNET(filter_mask_in) 120 #define V_bpf_mask_in VNET(bpf_mask_in) 121 #define V_filter_mask_out VNET(filter_mask_out) 122 #define V_bpf_mask_out VNET(bpf_mask_out) 123 124 static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 125 "enc sysctl"); 126 static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 127 "enc input sysctl"); 128 static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 129 "enc output sysctl"); 130 SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, 131 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0, 132 "IPsec input firewall filter mask"); 133 SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, 134 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0, 135 "IPsec input bpf mask"); 136 SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, 137 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0, 138 "IPsec output firewall filter mask"); 139 SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, 140 CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0, 141 "IPsec output bpf mask"); 142 143 static void 144 enc_clone_destroy(struct ifnet *ifp) 145 { 146 struct enc_softc *sc; 147 148 sc = ifp->if_softc; 149 KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc")); 150 151 bpfdetach(ifp); 152 if_detach(ifp); 153 if_free(ifp); 154 free(sc, M_DEVBUF); 155 V_enc_sc = NULL; 156 } 157 158 static int 159 enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 160 { 161 struct ifnet *ifp; 162 struct enc_softc *sc; 163 164 sc = malloc(sizeof(struct enc_softc), M_DEVBUF, 165 M_WAITOK | M_ZERO); 166 ifp = sc->sc_ifp = if_alloc(IFT_ENC); 167 if (ifp == NULL) { 168 free(sc, M_DEVBUF); 169 return (ENOSPC); 170 } 171 if (V_enc_sc != NULL) { 172 if_free(ifp); 173 free(sc, M_DEVBUF); 174 return (EEXIST); 175 } 176 V_enc_sc = sc; 177 if_initname(ifp, encname, unit); 178 ifp->if_mtu = ENCMTU; 179 ifp->if_ioctl = enc_ioctl; 180 ifp->if_output = enc_output; 181 ifp->if_softc = sc; 182 if_attach(ifp); 183 bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 184 return (0); 185 } 186 187 static int 188 enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 189 struct route *ro) 190 { 191 192 m_freem(m); 193 return (0); 194 } 195 196 static int 197 enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 198 { 199 200 if (cmd != SIOCSIFFLAGS) 201 return (EINVAL); 202 if (ifp->if_flags & IFF_UP) 203 ifp->if_drv_flags |= IFF_DRV_RUNNING; 204 else 205 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 206 return (0); 207 } 208 209 static void 210 enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, 211 int32_t hhook_type, uint8_t enc, uint8_t af) 212 { 213 struct enchdr hdr; 214 215 if (hhook_type == HHOOK_TYPE_IPSEC_IN && 216 (enc & V_bpf_mask_in) == 0) 217 return; 218 else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && 219 (enc & V_bpf_mask_out) == 0) 220 return; 221 if (bpf_peers_present(ifp->if_bpf) == 0) 222 return; 223 hdr.af = af; 224 hdr.spi = sav->spi; 225 hdr.flags = 0; 226 if (sav->alg_enc != SADB_EALG_NONE) 227 hdr.flags |= M_CONF; 228 if (sav->alg_auth != SADB_AALG_NONE) 229 hdr.flags |= M_AUTH; 230 bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); 231 } 232 233 /* 234 * One helper hook function is used by any hook points. 235 * + from hhook_type we can determine the packet direction: 236 * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT; 237 * + from hhook_id we can determine address family: AF_INET or AF_INET6; 238 * + udata contains pointer to enc_softc; 239 * + ctx_data contains pointer to struct ipsec_ctx_data. 240 */ 241 static int 242 enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, 243 void *hdata, struct osd *hosd) 244 { 245 struct ipsec_ctx_data *ctx; 246 struct enc_softc *sc; 247 struct ifnet *ifp, *rcvif; 248 struct pfil_head *ph; 249 int pdir; 250 251 sc = (struct enc_softc *)udata; 252 ifp = sc->sc_ifp; 253 if ((ifp->if_flags & IFF_UP) == 0) 254 return (0); 255 256 ctx = (struct ipsec_ctx_data *)ctx_data; 257 /* XXX: wrong hook point was used by caller? */ 258 if (ctx->af != hhook_id) 259 return (EPFNOSUPPORT); 260 261 enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); 262 switch (hhook_type) { 263 case HHOOK_TYPE_IPSEC_IN: 264 if (ctx->enc == IPSEC_ENC_BEFORE) { 265 /* Do accounting only once */ 266 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 267 if_inc_counter(ifp, IFCOUNTER_IBYTES, 268 (*ctx->mp)->m_pkthdr.len); 269 } 270 if ((ctx->enc & V_filter_mask_in) == 0) 271 return (0); /* skip pfil processing */ 272 pdir = PFIL_IN; 273 break; 274 case HHOOK_TYPE_IPSEC_OUT: 275 if (ctx->enc == IPSEC_ENC_BEFORE) { 276 /* Do accounting only once */ 277 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 278 if_inc_counter(ifp, IFCOUNTER_OBYTES, 279 (*ctx->mp)->m_pkthdr.len); 280 } 281 if ((ctx->enc & V_filter_mask_out) == 0) 282 return (0); /* skip pfil processing */ 283 pdir = PFIL_OUT; 284 break; 285 default: 286 return (EINVAL); 287 } 288 289 switch (hhook_id) { 290 #ifdef INET 291 case AF_INET: 292 ph = V_inet_pfil_head; 293 break; 294 #endif 295 #ifdef INET6 296 case AF_INET6: 297 ph = V_inet6_pfil_head; 298 break; 299 #endif 300 default: 301 ph = NULL; 302 } 303 if (ph == NULL || (pdir == PFIL_OUT && !PFIL_HOOKED_OUT(ph)) || 304 (pdir == PFIL_IN && !PFIL_HOOKED_IN(ph))) 305 return (0); 306 /* Make a packet looks like it was received on enc(4) */ 307 rcvif = (*ctx->mp)->m_pkthdr.rcvif; 308 (*ctx->mp)->m_pkthdr.rcvif = ifp; 309 if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != PFIL_PASS) { 310 *ctx->mp = NULL; /* consumed by filter */ 311 return (EACCES); 312 } 313 (*ctx->mp)->m_pkthdr.rcvif = rcvif; 314 enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, 315 IPSEC_ENC_AFTER_PFIL, ctx->af); 316 return (0); 317 } 318 319 static int 320 enc_add_hhooks(struct enc_softc *sc) 321 { 322 struct hookinfo hki; 323 int error; 324 325 error = EPFNOSUPPORT; 326 hki.hook_func = enc_hhook; 327 hki.hook_helper = NULL; 328 hki.hook_udata = sc; 329 #ifdef INET 330 hki.hook_id = AF_INET; 331 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 332 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 333 &hki, HHOOK_WAITOK); 334 if (error != 0) 335 return (error); 336 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 337 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 338 &hki, HHOOK_WAITOK); 339 if (error != 0) 340 return (error); 341 #endif 342 #ifdef INET6 343 hki.hook_id = AF_INET6; 344 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 345 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 346 &hki, HHOOK_WAITOK); 347 if (error != 0) 348 return (error); 349 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 350 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 351 &hki, HHOOK_WAITOK); 352 if (error != 0) 353 return (error); 354 #endif 355 return (error); 356 } 357 358 static void 359 enc_remove_hhooks(struct enc_softc *sc) 360 { 361 struct hookinfo hki; 362 363 hki.hook_func = enc_hhook; 364 hki.hook_helper = NULL; 365 hki.hook_udata = sc; 366 #ifdef INET 367 hki.hook_id = AF_INET; 368 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 369 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 370 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 371 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 372 #endif 373 #ifdef INET6 374 hki.hook_id = AF_INET6; 375 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 376 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 377 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 378 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 379 #endif 380 } 381 382 static void 383 vnet_enc_init(const void *unused __unused) 384 { 385 386 V_enc_sc = NULL; 387 V_enc_cloner = if_clone_simple(encname, enc_clone_create, 388 enc_clone_destroy, 1); 389 } 390 VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 391 vnet_enc_init, NULL); 392 393 static void 394 vnet_enc_init_proto(void *unused __unused) 395 { 396 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 397 398 if (enc_add_hhooks(V_enc_sc) != 0) 399 enc_clone_destroy(V_enc_sc->sc_ifp); 400 } 401 VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 402 vnet_enc_init_proto, NULL); 403 404 static void 405 vnet_enc_uninit(const void *unused __unused) 406 { 407 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 408 409 if_clone_detach(V_enc_cloner); 410 } 411 VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 412 vnet_enc_uninit, NULL); 413 414 /* 415 * The hhook consumer needs to go before ip[6]_destroy are called on 416 * SI_ORDER_THIRD. 417 */ 418 static void 419 vnet_enc_uninit_hhook(const void *unused __unused) 420 { 421 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 422 423 enc_remove_hhooks(V_enc_sc); 424 } 425 VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 426 vnet_enc_uninit_hhook, NULL); 427 428 static int 429 enc_modevent(module_t mod, int type, void *data) 430 { 431 432 switch (type) { 433 case MOD_LOAD: 434 case MOD_UNLOAD: 435 break; 436 default: 437 return (EOPNOTSUPP); 438 } 439 return (0); 440 } 441 442 static moduledata_t enc_mod = { 443 "if_enc", 444 enc_modevent, 445 0 446 }; 447 448 DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 449 MODULE_VERSION(if_enc, 1); 450