1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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, ret; 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 (pdir == PFIL_IN) 311 ret = pfil_mbuf_in(ph, ctx->mp, ifp, ctx->inp); 312 else 313 ret = pfil_mbuf_out(ph, ctx->mp, ifp, ctx->inp); 314 if (ret != PFIL_PASS) { 315 *ctx->mp = NULL; /* consumed by filter */ 316 return (EACCES); 317 } 318 (*ctx->mp)->m_pkthdr.rcvif = rcvif; 319 enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, 320 IPSEC_ENC_AFTER_PFIL, ctx->af); 321 return (0); 322 } 323 324 static int 325 enc_add_hhooks(struct enc_softc *sc) 326 { 327 struct hookinfo hki; 328 int error; 329 330 error = EPFNOSUPPORT; 331 hki.hook_func = enc_hhook; 332 hki.hook_helper = NULL; 333 hki.hook_udata = sc; 334 #ifdef INET 335 hki.hook_id = AF_INET; 336 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 337 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 338 &hki, HHOOK_WAITOK); 339 if (error != 0) 340 return (error); 341 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 342 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 343 &hki, HHOOK_WAITOK); 344 if (error != 0) 345 return (error); 346 #endif 347 #ifdef INET6 348 hki.hook_id = AF_INET6; 349 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 350 error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 351 &hki, HHOOK_WAITOK); 352 if (error != 0) 353 return (error); 354 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 355 error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 356 &hki, HHOOK_WAITOK); 357 if (error != 0) 358 return (error); 359 #endif 360 return (error); 361 } 362 363 static void 364 enc_remove_hhooks(struct enc_softc *sc) 365 { 366 struct hookinfo hki; 367 368 hki.hook_func = enc_hhook; 369 hki.hook_helper = NULL; 370 hki.hook_udata = sc; 371 #ifdef INET 372 hki.hook_id = AF_INET; 373 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 374 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 375 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 376 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 377 #endif 378 #ifdef INET6 379 hki.hook_id = AF_INET6; 380 hki.hook_type = HHOOK_TYPE_IPSEC_IN; 381 hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 382 hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 383 hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 384 #endif 385 } 386 387 static void 388 vnet_enc_init(const void *unused __unused) 389 { 390 391 V_enc_sc = NULL; 392 V_enc_cloner = if_clone_simple(encname, enc_clone_create, 393 enc_clone_destroy, 1); 394 } 395 VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 396 vnet_enc_init, NULL); 397 398 static void 399 vnet_enc_init_proto(void *unused __unused) 400 { 401 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 402 403 if (enc_add_hhooks(V_enc_sc) != 0) 404 enc_clone_destroy(V_enc_sc->sc_ifp); 405 } 406 VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 407 vnet_enc_init_proto, NULL); 408 409 static void 410 vnet_enc_uninit(const void *unused __unused) 411 { 412 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 413 414 if_clone_detach(V_enc_cloner); 415 } 416 VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 417 vnet_enc_uninit, NULL); 418 419 /* 420 * The hhook consumer needs to go before ip[6]_destroy are called on 421 * SI_ORDER_THIRD. 422 */ 423 static void 424 vnet_enc_uninit_hhook(const void *unused __unused) 425 { 426 KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 427 428 enc_remove_hhooks(V_enc_sc); 429 } 430 VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 431 vnet_enc_uninit_hhook, NULL); 432 433 static int 434 enc_modevent(module_t mod, int type, void *data) 435 { 436 437 switch (type) { 438 case MOD_LOAD: 439 case MOD_UNLOAD: 440 break; 441 default: 442 return (EOPNOTSUPP); 443 } 444 return (0); 445 } 446 447 static moduledata_t enc_mod = { 448 "if_enc", 449 enc_modevent, 450 0 451 }; 452 453 DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 454 MODULE_VERSION(if_enc, 1); 455