1 /*- 2 * Copyright (c) 2016 Yandex LLC 3 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/mbuf.h> 33 #include <sys/kernel.h> 34 #include <sys/lock.h> 35 #include <sys/rmlock.h> 36 #include <sys/socket.h> 37 #include <net/ethernet.h> 38 #include <net/if.h> 39 #include <net/if_pflog.h> 40 #include <net/if_var.h> 41 #include <net/if_clone.h> 42 #include <net/if_types.h> 43 #include <net/vnet.h> 44 #include <net/bpf.h> 45 46 #include <netinet/in.h> 47 #include <netinet/ip_fw.h> 48 #include <netinet/ip_var.h> 49 #include <netpfil/ipfw/ip_fw_private.h> 50 51 static VNET_DEFINE(struct ifnet *, log_if); 52 static VNET_DEFINE(struct ifnet *, pflog_if); 53 static VNET_DEFINE(struct if_clone *, ipfw_cloner); 54 static VNET_DEFINE(struct if_clone *, ipfwlog_cloner); 55 #define V_ipfw_cloner VNET(ipfw_cloner) 56 #define V_ipfwlog_cloner VNET(ipfwlog_cloner) 57 #define V_log_if VNET(log_if) 58 #define V_pflog_if VNET(pflog_if) 59 60 static struct rmlock log_if_lock; 61 #define LOGIF_LOCK_INIT(x) rm_init(&log_if_lock, "ipfw log_if lock") 62 #define LOGIF_LOCK_DESTROY(x) rm_destroy(&log_if_lock) 63 #define LOGIF_RLOCK_TRACKER struct rm_priotracker _log_tracker 64 #define LOGIF_RLOCK(x) rm_rlock(&log_if_lock, &_log_tracker) 65 #define LOGIF_RUNLOCK(x) rm_runlock(&log_if_lock, &_log_tracker) 66 #define LOGIF_WLOCK(x) rm_wlock(&log_if_lock) 67 #define LOGIF_WUNLOCK(x) rm_wunlock(&log_if_lock) 68 69 static const char ipfwname[] = "ipfw"; 70 static const char ipfwlogname[] = "ipfwlog"; 71 72 static int 73 ipfw_bpf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 74 { 75 76 return (EINVAL); 77 } 78 79 static int 80 ipfw_bpf_output(struct ifnet *ifp, struct mbuf *m, 81 const struct sockaddr *dst, struct route *ro) 82 { 83 84 if (m != NULL) 85 FREE_PKT(m); 86 return (0); 87 } 88 89 static void 90 ipfw_clone_destroy(struct ifnet *ifp) 91 { 92 93 LOGIF_WLOCK(); 94 if (ifp->if_hdrlen == ETHER_HDR_LEN) 95 V_log_if = NULL; 96 else 97 V_pflog_if = NULL; 98 LOGIF_WUNLOCK(); 99 100 bpfdetach(ifp); 101 if_detach(ifp); 102 if_free(ifp); 103 } 104 105 static int 106 ipfw_clone_create(struct if_clone *ifc, int unit, caddr_t params) 107 { 108 struct ifnet *ifp; 109 110 ifp = if_alloc(IFT_PFLOG); 111 if (ifp == NULL) 112 return (ENOSPC); 113 if_initname(ifp, ipfwname, unit); 114 ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; 115 ifp->if_mtu = 65536; 116 ifp->if_ioctl = ipfw_bpf_ioctl; 117 ifp->if_output = ipfw_bpf_output; 118 ifp->if_hdrlen = ETHER_HDR_LEN; 119 if_attach(ifp); 120 bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN); 121 LOGIF_WLOCK(); 122 if (V_log_if != NULL) { 123 LOGIF_WUNLOCK(); 124 bpfdetach(ifp); 125 if_detach(ifp); 126 if_free(ifp); 127 return (EEXIST); 128 } 129 V_log_if = ifp; 130 LOGIF_WUNLOCK(); 131 return (0); 132 } 133 134 static int 135 ipfwlog_clone_create(struct if_clone *ifc, int unit, caddr_t params) 136 { 137 struct ifnet *ifp; 138 139 ifp = if_alloc(IFT_PFLOG); 140 if (ifp == NULL) 141 return (ENOSPC); 142 if_initname(ifp, ipfwlogname, unit); 143 ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; 144 ifp->if_mtu = 65536; 145 ifp->if_ioctl = ipfw_bpf_ioctl; 146 ifp->if_output = ipfw_bpf_output; 147 ifp->if_hdrlen = PFLOG_HDRLEN; 148 if_attach(ifp); 149 bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 150 LOGIF_WLOCK(); 151 if (V_pflog_if != NULL) { 152 LOGIF_WUNLOCK(); 153 bpfdetach(ifp); 154 if_detach(ifp); 155 if_free(ifp); 156 return (EEXIST); 157 } 158 V_pflog_if = ifp; 159 LOGIF_WUNLOCK(); 160 return (0); 161 } 162 163 void 164 ipfw_bpf_mtap2(void *data, u_int dlen, struct mbuf *m) 165 { 166 LOGIF_RLOCK_TRACKER; 167 168 LOGIF_RLOCK(); 169 if (dlen == ETHER_HDR_LEN) { 170 if (V_log_if == NULL) { 171 LOGIF_RUNLOCK(); 172 return; 173 } 174 BPF_MTAP2(V_log_if, data, dlen, m); 175 } else if (dlen == PFLOG_HDRLEN) { 176 if (V_pflog_if == NULL) { 177 LOGIF_RUNLOCK(); 178 return; 179 } 180 BPF_MTAP2(V_pflog_if, data, dlen, m); 181 } 182 LOGIF_RUNLOCK(); 183 } 184 185 void 186 ipfw_bpf_init(int first) 187 { 188 189 if (first) { 190 LOGIF_LOCK_INIT(); 191 V_log_if = NULL; 192 V_pflog_if = NULL; 193 } 194 V_ipfw_cloner = if_clone_simple(ipfwname, ipfw_clone_create, 195 ipfw_clone_destroy, 0); 196 V_ipfwlog_cloner = if_clone_simple(ipfwlogname, ipfwlog_clone_create, 197 ipfw_clone_destroy, 0); 198 } 199 200 void 201 ipfw_bpf_uninit(int last) 202 { 203 204 if_clone_detach(V_ipfw_cloner); 205 if_clone_detach(V_ipfwlog_cloner); 206 if (last) 207 LOGIF_LOCK_DESTROY(); 208 } 209 210