]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/ip_fw_bpf.c
MFV r336490:
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfw / ip_fw_bpf.c
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