Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/pf/if_pflog.c
39536 views
1
/*-
2
* SPDX-License-Identifier: ISC
3
*
4
* The authors of this code are John Ioannidis ([email protected]),
5
* Angelos D. Keromytis ([email protected]) and
6
* Niels Provos ([email protected]).
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
#include "opt_inet.h"
41
#include "opt_inet6.h"
42
#include "opt_bpf.h"
43
#include "opt_pf.h"
44
45
#include <sys/param.h>
46
#include <sys/kernel.h>
47
#include <sys/mbuf.h>
48
#include <sys/module.h>
49
#include <sys/proc.h>
50
#include <sys/socket.h>
51
#include <sys/sockio.h>
52
53
#include <net/bpf.h>
54
#include <net/if.h>
55
#include <net/if_var.h>
56
#include <net/if_clone.h>
57
#include <net/if_pflog.h>
58
#include <net/if_private.h>
59
#include <net/if_types.h>
60
#include <net/vnet.h>
61
#include <net/pfvar.h>
62
63
#if defined(INET) || defined(INET6)
64
#include <netinet/in.h>
65
#endif
66
#ifdef INET
67
#include <netinet/in_var.h>
68
#include <netinet/ip.h>
69
#endif
70
71
#ifdef INET6
72
#include <netinet6/in6_var.h>
73
#include <netinet6/nd6.h>
74
#endif /* INET6 */
75
76
#ifdef INET
77
#include <machine/in_cksum.h>
78
#endif /* INET */
79
80
#define PFLOGMTU (32768 + MHLEN + MLEN)
81
82
#ifdef PFLOGDEBUG
83
#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0)
84
#else
85
#define DPRINTF(x)
86
#endif
87
88
static int pflogoutput(struct ifnet *, struct mbuf *,
89
const struct sockaddr *, struct route *);
90
static void pflogattach(int);
91
static int pflogifs_resize(size_t);
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 *, char *, size_t,
95
struct ifc_data *, struct ifnet **);
96
static int pflog_clone_destroy(struct if_clone *, struct ifnet *, uint32_t);
97
98
static const char pflogname[] = "pflog";
99
100
VNET_DEFINE_STATIC(struct if_clone *, pflog_cloner);
101
#define V_pflog_cloner VNET(pflog_cloner)
102
103
VNET_DEFINE_STATIC(int, npflogifs) = 0;
104
#define V_npflogifs VNET(npflogifs)
105
VNET_DEFINE(struct ifnet **, pflogifs); /* for fast access */
106
#define V_pflogifs VNET(pflogifs)
107
108
static void
109
pflogattach(int npflog __unused)
110
{
111
struct if_clone_addreq req = {
112
.create_f = pflog_clone_create,
113
.destroy_f = pflog_clone_destroy,
114
.flags = IFC_F_AUTOUNIT,
115
};
116
V_pflog_cloner = ifc_attach_cloner(pflogname, &req);
117
struct ifc_data ifd = { .unit = 0 };
118
ifc_create_ifp(pflogname, &ifd, NULL);
119
}
120
121
static int
122
pflogifs_resize(size_t n)
123
{
124
struct ifnet **p;
125
int i;
126
127
if (n > SIZE_MAX / sizeof(struct ifnet *))
128
return (EINVAL);
129
if (n == 0)
130
p = NULL;
131
else if ((p = malloc(n * sizeof(struct ifnet *), M_DEVBUF,
132
M_NOWAIT | M_ZERO)) == NULL)
133
return (ENOMEM);
134
for (i = 0; i < n; i++) {
135
if (i < V_npflogifs)
136
p[i] = V_pflogifs[i];
137
else
138
p[i] = NULL;
139
}
140
141
if (V_pflogifs)
142
free(V_pflogifs, M_DEVBUF);
143
V_pflogifs = p;
144
V_npflogifs = n;
145
146
return (0);
147
}
148
149
static int
150
pflog_clone_create(struct if_clone *ifc, char *name, size_t maxlen,
151
struct ifc_data *ifd, struct ifnet **ifpp)
152
{
153
struct ifnet *ifp;
154
155
ifp = if_alloc(IFT_PFLOG);
156
if_initname(ifp, pflogname, ifd->unit);
157
ifp->if_mtu = PFLOGMTU;
158
ifp->if_ioctl = pflogioctl;
159
ifp->if_output = pflogoutput;
160
ifp->if_start = pflogstart;
161
ifp->if_snd.ifq_maxlen = ifqmaxlen;
162
ifp->if_hdrlen = PFLOG_HDRLEN;
163
if_attach(ifp);
164
165
bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
166
167
if (ifd->unit + 1 > V_npflogifs &&
168
pflogifs_resize(ifd->unit + 1) != 0) {
169
pflog_clone_destroy(ifc, ifp, IFC_F_FORCE);
170
return (ENOMEM);
171
}
172
V_pflogifs[ifd->unit] = ifp;
173
*ifpp = ifp;
174
175
return (0);
176
}
177
178
static int
179
pflog_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
180
{
181
int i;
182
183
if (ifp->if_dunit == 0 && (flags & IFC_F_FORCE) == 0)
184
return (EINVAL);
185
186
for (i = 0; i < V_npflogifs; i++)
187
if (V_pflogifs[i] == ifp)
188
V_pflogifs[i] = NULL;
189
190
bpfdetach(ifp);
191
if_detach(ifp);
192
if_free(ifp);
193
194
return (0);
195
}
196
197
/*
198
* Start output on the pflog interface.
199
*/
200
static void
201
pflogstart(struct ifnet *ifp)
202
{
203
struct mbuf *m;
204
205
for (;;) {
206
IF_LOCK(&ifp->if_snd);
207
_IF_DEQUEUE(&ifp->if_snd, m);
208
IF_UNLOCK(&ifp->if_snd);
209
210
if (m == NULL)
211
return;
212
else
213
m_freem(m);
214
}
215
}
216
217
static int
218
pflogoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
219
struct route *rt)
220
{
221
m_freem(m);
222
return (0);
223
}
224
225
/* ARGSUSED */
226
static int
227
pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
228
{
229
switch (cmd) {
230
case SIOCSIFFLAGS:
231
if (ifp->if_flags & IFF_UP)
232
ifp->if_drv_flags |= IFF_DRV_RUNNING;
233
else
234
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
235
break;
236
default:
237
return (ENOTTY);
238
}
239
240
return (0);
241
}
242
243
static int
244
pflog_packet(uint8_t action, u_int8_t reason,
245
struct pf_krule *rm, struct pf_krule *am,
246
struct pf_kruleset *ruleset, struct pf_pdesc *pd, int lookupsafe,
247
struct pf_krule *trigger)
248
{
249
struct ifnet *ifn;
250
struct pfloghdr hdr;
251
252
if (rm == NULL || pd == NULL)
253
return (1);
254
if (trigger == NULL)
255
trigger = rm;
256
257
if (trigger->logif > V_npflogifs)
258
return (0);
259
260
ifn = V_pflogifs[trigger->logif];
261
if (ifn == NULL || !bpf_peers_present(ifn->if_bpf))
262
return (0);
263
264
bzero(&hdr, sizeof(hdr));
265
hdr.length = PFLOG_REAL_HDRLEN;
266
hdr.af = pd->af;
267
hdr.action = action;
268
hdr.reason = reason;
269
memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname));
270
271
if (am == NULL) {
272
hdr.rulenr = htonl(rm->nr);
273
hdr.subrulenr = -1;
274
} else {
275
hdr.rulenr = htonl(am->nr);
276
hdr.subrulenr = htonl(rm->nr);
277
if (ruleset != NULL && ruleset->anchor != NULL)
278
strlcpy(hdr.ruleset, ruleset->anchor->name,
279
sizeof(hdr.ruleset));
280
}
281
hdr.ridentifier = htonl(rm->ridentifier);
282
/*
283
* XXXGL: we avoid pf_socket_lookup() when we are holding
284
* state lock, since this leads to unsafe LOR.
285
* These conditions are very very rare, however.
286
*/
287
if (trigger->log & PF_LOG_USER && !pd->lookup.done && lookupsafe)
288
pd->lookup.done = pf_socket_lookup(pd);
289
if (trigger->log & PF_LOG_USER && pd->lookup.done > 0)
290
hdr.uid = pd->lookup.uid;
291
else
292
hdr.uid = -1;
293
hdr.pid = NO_PID;
294
hdr.rule_uid = rm->cuid;
295
hdr.rule_pid = rm->cpid;
296
hdr.dir = pd->dir;
297
298
#ifdef INET
299
if (pd->af == AF_INET && pd->dir == PF_OUT) {
300
struct ip *ip;
301
302
ip = mtod(pd->m, struct ip *);
303
ip->ip_sum = 0;
304
ip->ip_sum = in_cksum(pd->m, ip->ip_hl << 2);
305
}
306
#endif /* INET */
307
308
if_inc_counter(ifn, IFCOUNTER_OPACKETS, 1);
309
if_inc_counter(ifn, IFCOUNTER_OBYTES, pd->m->m_pkthdr.len);
310
bpf_mtap2(ifn->if_bpf, &hdr, PFLOG_HDRLEN, pd->m);
311
312
return (0);
313
}
314
315
static void
316
vnet_pflog_init(const void *unused __unused)
317
{
318
319
pflogattach(1);
320
}
321
VNET_SYSINIT(vnet_pflog_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY,
322
vnet_pflog_init, NULL);
323
324
static void
325
vnet_pflog_uninit(const void *unused __unused)
326
{
327
328
ifc_detach_cloner(V_pflog_cloner);
329
}
330
/*
331
* Detach after pf is gone; otherwise we might touch pflog memory
332
* from within pf after freeing pflog.
333
*/
334
VNET_SYSUNINIT(vnet_pflog_uninit, SI_SUB_INIT_IF, SI_ORDER_SECOND,
335
vnet_pflog_uninit, NULL);
336
337
static int
338
pflog_modevent(module_t mod, int type, void *data)
339
{
340
int error = 0;
341
342
switch (type) {
343
case MOD_LOAD:
344
PF_RULES_WLOCK();
345
pflog_packet_ptr = pflog_packet;
346
PF_RULES_WUNLOCK();
347
break;
348
case MOD_UNLOAD:
349
PF_RULES_WLOCK();
350
pflog_packet_ptr = NULL;
351
PF_RULES_WUNLOCK();
352
break;
353
default:
354
error = EOPNOTSUPP;
355
break;
356
}
357
358
return error;
359
}
360
361
static moduledata_t pflog_mod = { pflogname, pflog_modevent, 0 };
362
363
#define PFLOG_MODVER 1
364
365
/* Do not run before pf is initialized as we depend on its locks. */
366
DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY);
367
MODULE_VERSION(pflog, PFLOG_MODVER);
368
MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
369
370