Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/ipfw/ip_fw_bpf.c
108086 views
1
/*-
2
* Copyright (c) 2016 Yandex LLC
3
* Copyright (c) 2016 Andrey V. Elsukov <[email protected]>
4
* Copyright (c) 2025-2026 Gleb Smirnoff <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/mbuf.h>
31
#include <sys/kernel.h>
32
#include <sys/lock.h>
33
#include <sys/sx.h>
34
#include <sys/socket.h>
35
#include <sys/tree.h>
36
#include <net/ethernet.h>
37
#include <net/if.h>
38
#include <net/if_pflog.h>
39
#include <net/vnet.h>
40
#include <net/bpf.h>
41
42
#include <netinet/ip.h>
43
#include <netinet/ip_fw.h>
44
#include <netinet/ip_var.h>
45
#include <netpfil/ipfw/ip_fw_private.h>
46
47
static bool
48
bpf_ipfw_chkdir(void *arg __unused, const struct mbuf *m, int dir)
49
{
50
return ((dir == BPF_D_IN && m_rcvif(m) == NULL) ||
51
(dir == BPF_D_OUT && m_rcvif(m) != NULL));
52
}
53
54
static const struct bif_methods bpf_ipfw_methods = {
55
.bif_chkdir = bpf_ipfw_chkdir,
56
};
57
58
struct ipfw_tap {
59
RB_ENTRY(ipfw_tap) entry;
60
uint32_t rule;
61
u_int refs;
62
struct bpf_if *bpf;
63
char name[sizeof("ipfw4294967295")];
64
};
65
66
static inline int
67
tap_compare(const struct ipfw_tap *a, const struct ipfw_tap *b)
68
{
69
return (a->rule != b->rule ? (a->rule < b->rule ? -1 : 1) : 0);
70
}
71
RB_GENERATE_STATIC(tap_tree, ipfw_tap, entry, tap_compare);
72
VNET_DEFINE_STATIC(struct ipfw_tap, default_tap) = { .name = "ipfw0" };
73
#define V_default_tap VNET(default_tap)
74
75
void
76
ipfw_tap_alloc(struct ip_fw_chain *ch, uint32_t rule)
77
{
78
struct ipfw_tap *tap, key = { .rule = rule };
79
int n __diagused;
80
81
MPASS(rule > 0 && rule < IPFW_DEFAULT_RULE);
82
IPFW_UH_WLOCK_ASSERT(ch);
83
84
tap = RB_FIND(tap_tree, &ch->taps, &key);
85
if (tap != NULL) {
86
MPASS(tap->rule == rule);
87
tap->refs++;
88
return;
89
}
90
tap = malloc(sizeof(*tap), M_IPFW, M_WAITOK);
91
tap->rule = rule;
92
tap->refs = 1;
93
n = snprintf(tap->name, sizeof(tap->name), "ipfw%u", rule);
94
MPASS(n > 4 && n < sizeof("ipfw4294967295"));
95
tap->bpf = bpf_attach(tap->name, DLT_EN10MB, PFLOG_HDRLEN,
96
&bpf_ipfw_methods, NULL);
97
tap = RB_INSERT(tap_tree, &ch->taps, tap);
98
MPASS(tap == NULL);
99
}
100
101
void
102
ipfw_tap_free(struct ip_fw_chain *ch, uint32_t rule)
103
{
104
struct ipfw_tap *tap, key = { .rule = rule };
105
106
MPASS(rule > 0 && rule < IPFW_DEFAULT_RULE);
107
IPFW_UH_WLOCK_ASSERT(ch);
108
109
tap = RB_FIND(tap_tree, &ch->taps, &key);
110
MPASS(tap != NULL);
111
if (--tap->refs == 0) {
112
bpf_detach(tap->bpf);
113
RB_REMOVE(tap_tree, &ch->taps, tap);
114
free(tap, M_IPFW);
115
}
116
}
117
118
void
119
ipfw_bpf_tap(struct ip_fw_chain *ch, struct ip_fw_args *args,
120
struct ip *ip, uint32_t rulenum)
121
{
122
struct ipfw_tap *tap;
123
124
if (rulenum == IPFW_DEFAULT_RULE) {
125
tap = &V_default_tap;
126
} else {
127
struct ipfw_tap key = { .rule = rulenum };
128
129
tap = RB_FIND(tap_tree, &ch->taps, &key);
130
MPASS(tap != NULL);
131
/*
132
* Compatibility: if user is not using per-rule taps, fallback
133
* to the default tap.
134
*/
135
if (!bpf_peers_present(tap->bpf))
136
tap = &V_default_tap;
137
}
138
if (args->flags & IPFW_ARGS_LENMASK) {
139
bpf_tap(tap->bpf, args->mem, IPFW_ARGS_LENGTH(args->flags));
140
} else if (args->flags & IPFW_ARGS_ETHER) {
141
/* layer2, use orig hdr */
142
bpf_mtap(tap->bpf, args->m);
143
} else {
144
char *fakehdr;
145
146
/* Add fake header. Later we will store
147
* more info in the header.
148
*/
149
if (ip->ip_v == 4)
150
fakehdr = "DDDDDDSSSSSS\x08\x00";
151
else if (ip->ip_v == 6)
152
fakehdr = "DDDDDDSSSSSS\x86\xdd";
153
else
154
/* Obviously bogus EtherType. */
155
fakehdr = "DDDDDDSSSSSS\xff\xff";
156
157
bpf_mtap2(tap->bpf, fakehdr, ETHER_HDR_LEN, args->m);
158
}
159
}
160
161
VNET_DEFINE_STATIC(struct bpf_if *, bpf_pflog);
162
#define V_bpf_pflog VNET(bpf_pflog)
163
void
164
ipfw_pflog_tap(void *data, struct mbuf *m)
165
{
166
bpf_mtap2(V_bpf_pflog, data, PFLOG_HDRLEN, m);
167
}
168
169
void
170
ipfw_bpf_init(int first __unused)
171
{
172
V_default_tap.bpf = bpf_attach(V_default_tap.name, DLT_EN10MB,
173
PFLOG_HDRLEN, &bpf_ipfw_methods, NULL);
174
V_bpf_pflog = bpf_attach("ipfwlog0", DLT_PFLOG, PFLOG_HDRLEN,
175
&bpf_ipfw_methods, NULL);
176
}
177
178
void
179
ipfw_bpf_uninit(int last __unused)
180
{
181
bpf_detach(V_default_tap.bpf);
182
bpf_detach(V_bpf_pflog);
183
}
184
185