]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/pf/if_pflog.c
pf: Split pfi_kif into a user and kernel space structure
[FreeBSD/FreeBSD.git] / sys / netpfil / pf / if_pflog.c
1 /*-
2  * SPDX-License-Identifier: ISC
3  *
4  * The authors of this code are John Ioannidis (ji@tla.org),
5  * Angelos D. Keromytis (kermit@csd.uch.gr) and
6  * Niels Provos (provos@physnet.uni-hamburg.de).
7  *
8  * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
9  * in November 1995.
10  *
11  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12  * by Angelos D. Keromytis.
13  *
14  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15  * and Niels Provos.
16  *
17  * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
18  * and Niels Provos.
19  * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
20  *
21  * Permission to use, copy, and modify this software with or without fee
22  * is hereby granted, provided that this entire notice is included in
23  * all copies of any software which is or includes a copy or
24  * modification of this software.
25  * You may use this code under the GNU public license if you so wish. Please
26  * contribute changes back to the authors under this freer than GPL license
27  * so that we may further the use of strong encryption without limitations to
28  * all.
29  *
30  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
31  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
32  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
33  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
34  * PURPOSE.
35  *
36  *      $OpenBSD: if_pflog.c,v 1.26 2007/10/18 21:58:18 mpf Exp $
37  */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include "opt_inet.h"
43 #include "opt_inet6.h"
44 #include "opt_bpf.h"
45 #include "opt_pf.h"
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/mbuf.h>
50 #include <sys/module.h>
51 #include <sys/proc.h>
52 #include <sys/socket.h>
53 #include <sys/sockio.h>
54
55 #include <net/bpf.h>
56 #include <net/if.h>
57 #include <net/if_var.h>
58 #include <net/if_clone.h>
59 #include <net/if_pflog.h>
60 #include <net/if_types.h>
61 #include <net/vnet.h>
62 #include <net/pfvar.h>
63
64 #if defined(INET) || defined(INET6)
65 #include <netinet/in.h>
66 #endif
67 #ifdef  INET
68 #include <netinet/in_var.h>
69 #include <netinet/ip.h>
70 #endif
71
72 #ifdef INET6
73 #include <netinet6/in6_var.h>
74 #include <netinet6/nd6.h>
75 #endif /* INET6 */
76
77 #ifdef INET
78 #include <machine/in_cksum.h>
79 #endif /* INET */
80
81 #define PFLOGMTU        (32768 + MHLEN + MLEN)
82
83 #ifdef PFLOGDEBUG
84 #define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
85 #else
86 #define DPRINTF(x)
87 #endif
88
89 static int      pflogoutput(struct ifnet *, struct mbuf *,
90                     const struct sockaddr *, struct route *);
91 static void     pflogattach(int);
92 static int      pflogioctl(struct ifnet *, u_long, caddr_t);
93 static void     pflogstart(struct ifnet *);
94 static int      pflog_clone_create(struct if_clone *, int, caddr_t);
95 static void     pflog_clone_destroy(struct ifnet *);
96
97 static const char pflogname[] = "pflog";
98
99 VNET_DEFINE_STATIC(struct if_clone *, pflog_cloner);
100 #define V_pflog_cloner          VNET(pflog_cloner)
101
102 VNET_DEFINE(struct ifnet *, pflogifs[PFLOGIFS_MAX]);    /* for fast access */
103 #define V_pflogifs              VNET(pflogifs)
104
105 static void
106 pflogattach(int npflog __unused)
107 {
108         int     i;
109         for (i = 0; i < PFLOGIFS_MAX; i++)
110                 V_pflogifs[i] = NULL;
111         V_pflog_cloner = if_clone_simple(pflogname, pflog_clone_create,
112             pflog_clone_destroy, 1);
113 }
114
115 static int
116 pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param)
117 {
118         struct ifnet *ifp;
119
120         if (unit >= PFLOGIFS_MAX)
121                 return (EINVAL);
122
123         ifp = if_alloc(IFT_PFLOG);
124         if (ifp == NULL) {
125                 return (ENOSPC);
126         }
127         if_initname(ifp, pflogname, unit);
128         ifp->if_mtu = PFLOGMTU;
129         ifp->if_ioctl = pflogioctl;
130         ifp->if_output = pflogoutput;
131         ifp->if_start = pflogstart;
132         ifp->if_snd.ifq_maxlen = ifqmaxlen;
133         ifp->if_hdrlen = PFLOG_HDRLEN;
134         if_attach(ifp);
135
136         bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
137
138         V_pflogifs[unit] = ifp;
139
140         return (0);
141 }
142
143 static void
144 pflog_clone_destroy(struct ifnet *ifp)
145 {
146         int i;
147
148         for (i = 0; i < PFLOGIFS_MAX; i++)
149                 if (V_pflogifs[i] == ifp)
150                         V_pflogifs[i] = NULL;
151
152         bpfdetach(ifp);
153         if_detach(ifp);
154         if_free(ifp);
155 }
156
157 /*
158  * Start output on the pflog interface.
159  */
160 static void
161 pflogstart(struct ifnet *ifp)
162 {
163         struct mbuf *m;
164
165         for (;;) {
166                 IF_LOCK(&ifp->if_snd);
167                 _IF_DEQUEUE(&ifp->if_snd, m);
168                 IF_UNLOCK(&ifp->if_snd);
169
170                 if (m == NULL)
171                         return;
172                 else
173                         m_freem(m);
174         }
175 }
176
177 static int
178 pflogoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
179         struct route *rt)
180 {
181         m_freem(m);
182         return (0);
183 }
184
185 /* ARGSUSED */
186 static int
187 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
188 {
189         switch (cmd) {
190         case SIOCSIFFLAGS:
191                 if (ifp->if_flags & IFF_UP)
192                         ifp->if_drv_flags |= IFF_DRV_RUNNING;
193                 else
194                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
195                 break;
196         default:
197                 return (ENOTTY);
198         }
199
200         return (0);
201 }
202
203 static int
204 pflog_packet(struct pfi_kkif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
205     u_int8_t reason, struct pf_krule *rm, struct pf_krule *am,
206     struct pf_kruleset *ruleset, struct pf_pdesc *pd, int lookupsafe)
207 {
208         struct ifnet *ifn;
209         struct pfloghdr hdr;
210
211         if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
212                 return ( 1);
213
214         if ((ifn = V_pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
215                 return (0);
216
217         bzero(&hdr, sizeof(hdr));
218         hdr.length = PFLOG_REAL_HDRLEN;
219         hdr.af = af;
220         hdr.action = rm->action;
221         hdr.reason = reason;
222         memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
223
224         if (am == NULL) {
225                 hdr.rulenr = htonl(rm->nr);
226                 hdr.subrulenr = -1;
227         } else {
228                 hdr.rulenr = htonl(am->nr);
229                 hdr.subrulenr = htonl(rm->nr);
230                 if (ruleset != NULL && ruleset->anchor != NULL)
231                         strlcpy(hdr.ruleset, ruleset->anchor->name,
232                             sizeof(hdr.ruleset));
233         }
234         /*
235          * XXXGL: we avoid pf_socket_lookup() when we are holding
236          * state lock, since this leads to unsafe LOR.
237          * These conditions are very very rare, however.
238          */
239         if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe)
240                 pd->lookup.done = pf_socket_lookup(dir, pd, m);
241         if (pd->lookup.done > 0)
242                 hdr.uid = pd->lookup.uid;
243         else
244                 hdr.uid = UID_MAX;
245         hdr.pid = NO_PID;
246         hdr.rule_uid = rm->cuid;
247         hdr.rule_pid = rm->cpid;
248         hdr.dir = dir;
249
250 #ifdef INET
251         if (af == AF_INET && dir == PF_OUT) {
252                 struct ip *ip;
253
254                 ip = mtod(m, struct ip *);
255                 ip->ip_sum = 0;
256                 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
257         }
258 #endif /* INET */
259
260         if_inc_counter(ifn, IFCOUNTER_OPACKETS, 1);
261         if_inc_counter(ifn, IFCOUNTER_OBYTES, m->m_pkthdr.len);
262         BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m);
263
264         return (0);
265 }
266
267 static void
268 vnet_pflog_init(const void *unused __unused)
269 {
270
271         pflogattach(1);
272 }
273 VNET_SYSINIT(vnet_pflog_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY,
274     vnet_pflog_init, NULL);
275
276 static void
277 vnet_pflog_uninit(const void *unused __unused)
278 {
279
280         if_clone_detach(V_pflog_cloner);
281 }
282 /*
283  * Detach after pf is gone; otherwise we might touch pflog memory
284  * from within pf after freeing pflog.
285  */
286 VNET_SYSUNINIT(vnet_pflog_uninit, SI_SUB_INIT_IF, SI_ORDER_SECOND,
287     vnet_pflog_uninit, NULL);
288
289 static int
290 pflog_modevent(module_t mod, int type, void *data)
291 {
292         int error = 0;
293
294         switch (type) {
295         case MOD_LOAD:
296                 PF_RULES_WLOCK();
297                 pflog_packet_ptr = pflog_packet;
298                 PF_RULES_WUNLOCK();
299                 break;
300         case MOD_UNLOAD:
301                 PF_RULES_WLOCK();
302                 pflog_packet_ptr = NULL;
303                 PF_RULES_WUNLOCK();
304                 break;
305         default:
306                 error = EOPNOTSUPP;
307                 break;
308         }
309
310         return error;
311 }
312
313 static moduledata_t pflog_mod = { pflogname, pflog_modevent, 0 };
314
315 #define PFLOG_MODVER 1
316
317 /* Do not run before pf is initialized as we depend on its locks. */
318 DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY);
319 MODULE_VERSION(pflog, PFLOG_MODVER);
320 MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);