1bdea400fSAndrew Thompson /*- 2bdea400fSAndrew Thompson * Copyright (c) 2006 The FreeBSD Project. 3bdea400fSAndrew Thompson * All rights reserved. 4bdea400fSAndrew Thompson * 5bdea400fSAndrew Thompson * Redistribution and use in source and binary forms, with or without 6bdea400fSAndrew Thompson * modification, are permitted provided that the following conditions 7bdea400fSAndrew Thompson * are met: 8bdea400fSAndrew Thompson * 9bdea400fSAndrew Thompson * 1. Redistributions of source code must retain the above copyright 10bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer. 11bdea400fSAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 12bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer in the 13bdea400fSAndrew Thompson * documentation and/or other materials provided with the distribution. 14bdea400fSAndrew Thompson * 15bdea400fSAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16bdea400fSAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17bdea400fSAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18bdea400fSAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19bdea400fSAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20bdea400fSAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21bdea400fSAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22bdea400fSAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23bdea400fSAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24bdea400fSAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25bdea400fSAndrew Thompson * SUCH DAMAGE. 26bdea400fSAndrew Thompson * 27bdea400fSAndrew Thompson * $FreeBSD$ 28bdea400fSAndrew Thompson */ 29bdea400fSAndrew Thompson 30bdea400fSAndrew Thompson #include <sys/param.h> 31bdea400fSAndrew Thompson #include <sys/systm.h> 32bdea400fSAndrew Thompson #include <sys/kernel.h> 33bdea400fSAndrew Thompson #include <sys/malloc.h> 34bdea400fSAndrew Thompson #include <sys/mbuf.h> 35bdea400fSAndrew Thompson #include <sys/module.h> 36bdea400fSAndrew Thompson #include <machine/bus.h> 37bdea400fSAndrew Thompson #include <sys/rman.h> 38bdea400fSAndrew Thompson #include <sys/socket.h> 39bdea400fSAndrew Thompson #include <sys/sockio.h> 40bdea400fSAndrew Thompson #include <sys/sysctl.h> 41bdea400fSAndrew Thompson 42bdea400fSAndrew Thompson #include <net/if.h> 43bdea400fSAndrew Thompson #include <net/if_clone.h> 44bdea400fSAndrew Thompson #include <net/if_types.h> 45bdea400fSAndrew Thompson #include <net/pfil.h> 46bdea400fSAndrew Thompson #include <net/route.h> 47bdea400fSAndrew Thompson #include <net/netisr.h> 48bdea400fSAndrew Thompson #include <net/bpf.h> 49bdea400fSAndrew Thompson #include <net/bpfdesc.h> 50bdea400fSAndrew Thompson 51bdea400fSAndrew Thompson #include <netinet/in.h> 52bdea400fSAndrew Thompson #include <netinet/in_systm.h> 53bdea400fSAndrew Thompson #include <netinet/ip.h> 54bdea400fSAndrew Thompson #include <netinet/ip_var.h> 55bdea400fSAndrew Thompson #include <netinet/in_var.h> 56bdea400fSAndrew Thompson #include "opt_inet6.h" 57bdea400fSAndrew Thompson 58bdea400fSAndrew Thompson #ifdef INET6 59bdea400fSAndrew Thompson #include <netinet/ip6.h> 60bdea400fSAndrew Thompson #include <netinet6/ip6_var.h> 61bdea400fSAndrew Thompson #endif 62bdea400fSAndrew Thompson 63bdea400fSAndrew Thompson #include <netipsec/ipsec.h> 64bdea400fSAndrew Thompson 65bdea400fSAndrew Thompson #define ENCMTU (1024+512) 66bdea400fSAndrew Thompson #define ENC_HDRLEN 12 67bdea400fSAndrew Thompson 68bdea400fSAndrew Thompson /* XXX this define must have the same value as in OpenBSD */ 69bdea400fSAndrew Thompson #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 70bdea400fSAndrew Thompson #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 71bdea400fSAndrew Thompson #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 72bdea400fSAndrew Thompson 73bdea400fSAndrew Thompson struct enchdr { 74bdea400fSAndrew Thompson u_int32_t af; 75bdea400fSAndrew Thompson u_int32_t spi; 76bdea400fSAndrew Thompson u_int32_t flags; 77bdea400fSAndrew Thompson }; 78bdea400fSAndrew Thompson 79bdea400fSAndrew Thompson static struct ifnet *encif; 80bdea400fSAndrew Thompson static struct mtx enc_mtx; 81bdea400fSAndrew Thompson 82bdea400fSAndrew Thompson struct enc_softc { 83bdea400fSAndrew Thompson struct ifnet *sc_ifp; 84bdea400fSAndrew Thompson }; 85bdea400fSAndrew Thompson 86bdea400fSAndrew Thompson static int enc_ioctl(struct ifnet *, u_long, caddr_t); 87bdea400fSAndrew Thompson static int enc_output(struct ifnet *ifp, struct mbuf *m, 88bdea400fSAndrew Thompson struct sockaddr *dst, struct rtentry *rt); 89bdea400fSAndrew Thompson static int enc_clone_create(struct if_clone *, int); 90bdea400fSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 91bdea400fSAndrew Thompson 92bdea400fSAndrew Thompson IFC_SIMPLE_DECLARE(enc, 1); 93bdea400fSAndrew Thompson 94bdea400fSAndrew Thompson static void 95bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 96bdea400fSAndrew Thompson { 97bdea400fSAndrew Thompson 98bdea400fSAndrew Thompson KASSERT(encif == ifp, ("%s: unknown ifnet", __func__)); 99bdea400fSAndrew Thompson 100bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 101bdea400fSAndrew Thompson encif = NULL; 102bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 103bdea400fSAndrew Thompson 104bdea400fSAndrew Thompson bpfdetach(ifp); 105bdea400fSAndrew Thompson if_detach(ifp); 106bdea400fSAndrew Thompson if_free(ifp); 107bdea400fSAndrew Thompson 108bdea400fSAndrew Thompson } 109bdea400fSAndrew Thompson 110bdea400fSAndrew Thompson static int 111bdea400fSAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit) 112bdea400fSAndrew Thompson { 113bdea400fSAndrew Thompson struct ifnet *ifp; 114bdea400fSAndrew Thompson struct enc_softc *sc; 115bdea400fSAndrew Thompson 116bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 117bdea400fSAndrew Thompson if (encif != NULL) 118bdea400fSAndrew Thompson return (EBUSY); 119bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 120bdea400fSAndrew Thompson 121bdea400fSAndrew Thompson sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 122bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 123bdea400fSAndrew Thompson if (ifp == NULL) { 124bdea400fSAndrew Thompson free(sc, M_DEVBUF); 125bdea400fSAndrew Thompson return (ENOSPC); 126bdea400fSAndrew Thompson } 127bdea400fSAndrew Thompson 128bdea400fSAndrew Thompson if_initname(ifp, ifc->ifc_name, unit); 129bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 130bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 131bdea400fSAndrew Thompson ifp->if_output = enc_output; 132bdea400fSAndrew Thompson ifp->if_snd.ifq_maxlen = ifqmaxlen; 133bdea400fSAndrew Thompson ifp->if_softc = sc; 134bdea400fSAndrew Thompson if_attach(ifp); 135bdea400fSAndrew Thompson bpfattach(ifp, DLT_ENC, ENC_HDRLEN); 136bdea400fSAndrew Thompson 137bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 138bdea400fSAndrew Thompson encif = ifp; 139bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 140bdea400fSAndrew Thompson 141bdea400fSAndrew Thompson return (0); 142bdea400fSAndrew Thompson } 143bdea400fSAndrew Thompson 144bdea400fSAndrew Thompson static int 145bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 146bdea400fSAndrew Thompson { 147bdea400fSAndrew Thompson switch (type) { 148bdea400fSAndrew Thompson case MOD_LOAD: 149bdea400fSAndrew Thompson mtx_init(&enc_mtx, "enc mtx", NULL, MTX_DEF); 150bdea400fSAndrew Thompson if_clone_attach(&enc_cloner); 151bdea400fSAndrew Thompson break; 152bdea400fSAndrew Thompson case MOD_UNLOAD: 153bdea400fSAndrew Thompson printf("enc module unload - not possible for this module\n"); 154bdea400fSAndrew Thompson return (EINVAL); 155bdea400fSAndrew Thompson default: 156bdea400fSAndrew Thompson return (EOPNOTSUPP); 157bdea400fSAndrew Thompson } 158bdea400fSAndrew Thompson return (0); 159bdea400fSAndrew Thompson } 160bdea400fSAndrew Thompson 161bdea400fSAndrew Thompson static moduledata_t enc_mod = { 162bdea400fSAndrew Thompson "enc", 163bdea400fSAndrew Thompson enc_modevent, 164bdea400fSAndrew Thompson 0 165bdea400fSAndrew Thompson }; 166bdea400fSAndrew Thompson 167bdea400fSAndrew Thompson DECLARE_MODULE(enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 168bdea400fSAndrew Thompson 169bdea400fSAndrew Thompson static int 170bdea400fSAndrew Thompson enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 171bdea400fSAndrew Thompson struct rtentry *rt) 172bdea400fSAndrew Thompson { 173bdea400fSAndrew Thompson m_freem(m); 174bdea400fSAndrew Thompson return (0); 175bdea400fSAndrew Thompson } 176bdea400fSAndrew Thompson 177bdea400fSAndrew Thompson /* 178bdea400fSAndrew Thompson * Process an ioctl request. 179bdea400fSAndrew Thompson */ 180bdea400fSAndrew Thompson /* ARGSUSED */ 181bdea400fSAndrew Thompson static int 182bdea400fSAndrew Thompson enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 183bdea400fSAndrew Thompson { 184bdea400fSAndrew Thompson int error = 0; 185bdea400fSAndrew Thompson 186bdea400fSAndrew Thompson switch (cmd) { 187bdea400fSAndrew Thompson 188bdea400fSAndrew Thompson case SIOCSIFFLAGS: 189bdea400fSAndrew Thompson if (ifp->if_flags & IFF_UP) 190bdea400fSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_RUNNING; 191bdea400fSAndrew Thompson else 192bdea400fSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 193bdea400fSAndrew Thompson 194bdea400fSAndrew Thompson break; 195bdea400fSAndrew Thompson 196bdea400fSAndrew Thompson default: 197bdea400fSAndrew Thompson error = EINVAL; 198bdea400fSAndrew Thompson } 199bdea400fSAndrew Thompson return (error); 200bdea400fSAndrew Thompson } 201bdea400fSAndrew Thompson 202bdea400fSAndrew Thompson int 203bdea400fSAndrew Thompson ipsec_filter(struct mbuf **mp, int dir) 204bdea400fSAndrew Thompson { 205bdea400fSAndrew Thompson int error, i; 206bdea400fSAndrew Thompson struct ip *ip; 207bdea400fSAndrew Thompson 208bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 209bdea400fSAndrew Thompson if (encif == NULL || (encif->if_drv_flags & IFF_DRV_RUNNING) == 0) { 210bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 211bdea400fSAndrew Thompson return (0); 212bdea400fSAndrew Thompson } 213bdea400fSAndrew Thompson 214bdea400fSAndrew Thompson /* Skip pfil(9) if no filters are loaded */ 215bdea400fSAndrew Thompson if (!(PFIL_HOOKED(&inet_pfil_hook) 216bdea400fSAndrew Thompson #ifdef INET6 217bdea400fSAndrew Thompson || PFIL_HOOKED(&inet6_pfil_hook) 218bdea400fSAndrew Thompson #endif 219bdea400fSAndrew Thompson )) { 220bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 221bdea400fSAndrew Thompson return (0); 222bdea400fSAndrew Thompson } 223bdea400fSAndrew Thompson 224bdea400fSAndrew Thompson i = min((*mp)->m_pkthdr.len, max_protohdr); 225bdea400fSAndrew Thompson if ((*mp)->m_len < i) { 226bdea400fSAndrew Thompson *mp = m_pullup(*mp, i); 227bdea400fSAndrew Thompson if (*mp == NULL) { 228bdea400fSAndrew Thompson printf("%s: m_pullup failed\n", __func__); 229bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 230bdea400fSAndrew Thompson return (-1); 231bdea400fSAndrew Thompson } 232bdea400fSAndrew Thompson } 233bdea400fSAndrew Thompson 234bdea400fSAndrew Thompson error = 0; 235bdea400fSAndrew Thompson ip = mtod(*mp, struct ip *); 236bdea400fSAndrew Thompson switch (ip->ip_v) { 237bdea400fSAndrew Thompson case 4: 238bdea400fSAndrew Thompson /* 239bdea400fSAndrew Thompson * before calling the firewall, swap fields the same as 240bdea400fSAndrew Thompson * IP does. here we assume the header is contiguous 241bdea400fSAndrew Thompson */ 242bdea400fSAndrew Thompson ip->ip_len = ntohs(ip->ip_len); 243bdea400fSAndrew Thompson ip->ip_off = ntohs(ip->ip_off); 244bdea400fSAndrew Thompson 245bdea400fSAndrew Thompson error = pfil_run_hooks(&inet_pfil_hook, mp, 246bdea400fSAndrew Thompson encif, dir, NULL); 247bdea400fSAndrew Thompson 248bdea400fSAndrew Thompson if (*mp == NULL || error != 0) 249bdea400fSAndrew Thompson break; 250bdea400fSAndrew Thompson 251bdea400fSAndrew Thompson /* restore byte ordering */ 252bdea400fSAndrew Thompson ip = mtod(*mp, struct ip *); 253bdea400fSAndrew Thompson ip->ip_len = htons(ip->ip_len); 254bdea400fSAndrew Thompson ip->ip_off = htons(ip->ip_off); 255bdea400fSAndrew Thompson break; 256bdea400fSAndrew Thompson 257bdea400fSAndrew Thompson #ifdef INET6 258bdea400fSAndrew Thompson case 6: 259bdea400fSAndrew Thompson error = pfil_run_hooks(&inet6_pfil_hook, mp, 260bdea400fSAndrew Thompson encif, dir, NULL); 261bdea400fSAndrew Thompson break; 262bdea400fSAndrew Thompson #endif 263bdea400fSAndrew Thompson default: 264bdea400fSAndrew Thompson printf("%s: unknown IP version\n", __func__); 265bdea400fSAndrew Thompson } 266bdea400fSAndrew Thompson 267bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 268bdea400fSAndrew Thompson if (*mp == NULL) 269bdea400fSAndrew Thompson return (error); 270bdea400fSAndrew Thompson if (error != 0) 271bdea400fSAndrew Thompson goto bad; 272bdea400fSAndrew Thompson 273bdea400fSAndrew Thompson return (error); 274bdea400fSAndrew Thompson 275bdea400fSAndrew Thompson bad: 276bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 277bdea400fSAndrew Thompson m_freem(*mp); 278bdea400fSAndrew Thompson *mp = NULL; 279bdea400fSAndrew Thompson return (error); 280bdea400fSAndrew Thompson } 281bdea400fSAndrew Thompson 282bdea400fSAndrew Thompson void 283bdea400fSAndrew Thompson ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af) 284bdea400fSAndrew Thompson { 285bdea400fSAndrew Thompson int flags; 286bdea400fSAndrew Thompson struct enchdr hdr; 287bdea400fSAndrew Thompson struct mbuf m1; 288bdea400fSAndrew Thompson 289bdea400fSAndrew Thompson KASSERT(sav != NULL, ("%s: sav is null", __func__)); 290bdea400fSAndrew Thompson 291bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 292bdea400fSAndrew Thompson if (encif == NULL || (encif->if_drv_flags & IFF_DRV_RUNNING) == 0) { 293bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 294bdea400fSAndrew Thompson return; 295bdea400fSAndrew Thompson } 296bdea400fSAndrew Thompson 297bdea400fSAndrew Thompson if (encif->if_bpf) { 298bdea400fSAndrew Thompson flags = 0; 299bdea400fSAndrew Thompson if (sav->alg_enc != SADB_EALG_NONE) 300bdea400fSAndrew Thompson flags |= M_CONF; 301bdea400fSAndrew Thompson if (sav->alg_auth != SADB_AALG_NONE) 302bdea400fSAndrew Thompson flags |= M_AUTH; 303bdea400fSAndrew Thompson 304bdea400fSAndrew Thompson /* 305bdea400fSAndrew Thompson * We need to prepend the address family as a four byte 306bdea400fSAndrew Thompson * field. Cons up a dummy header to pacify bpf. This 307bdea400fSAndrew Thompson * is safe because bpf will only read from the mbuf 308bdea400fSAndrew Thompson * (i.e., it won't try to free it or keep a pointer a 309bdea400fSAndrew Thompson * to it). 310bdea400fSAndrew Thompson */ 311bdea400fSAndrew Thompson hdr.af = af; 312bdea400fSAndrew Thompson hdr.spi = sav->spi; 313bdea400fSAndrew Thompson hdr.flags = flags; 314bdea400fSAndrew Thompson 315bdea400fSAndrew Thompson m1.m_flags = 0; 316bdea400fSAndrew Thompson m1.m_next = m; 317bdea400fSAndrew Thompson m1.m_len = ENC_HDRLEN; 318bdea400fSAndrew Thompson m1.m_data = (char *) &hdr; 319bdea400fSAndrew Thompson 320bdea400fSAndrew Thompson bpf_mtap(encif->if_bpf, &m1); 321bdea400fSAndrew Thompson } 322bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 323bdea400fSAndrew Thompson } 324