]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
87b515ed | 22 | #include "bpf-filter.hh" |
becba800 | 23 | #include "iputils.hh" |
dc22be50 | 24 | #include "dolog.hh" |
87b515ed RG |
25 | |
26 | #ifdef HAVE_EBPF | |
27 | ||
28 | #include <sys/syscall.h> | |
dc22be50 | 29 | #include <sys/resource.h> |
87b515ed RG |
30 | #include <linux/bpf.h> |
31 | ||
32 | #include "ext/libbpf/libbpf.h" | |
33 | ||
16f0c288 OM |
34 | #include "misc.hh" |
35 | ||
4a94ee50 | 36 | static __u64 ptr_to_u64(const void *ptr) |
87b515ed RG |
37 | { |
38 | return (__u64) (unsigned long) ptr; | |
39 | } | |
40 | ||
38b10979 | 41 | /* these can be static as they are not declared in libbpf.h: */ |
4a94ee50 | 42 | static int bpf_pin_map(int descriptor, const std::string& path) |
ad6bca0e RG |
43 | { |
44 | union bpf_attr attr; | |
45 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 RG |
46 | attr.bpf_fd = descriptor; |
47 | attr.pathname = ptr_to_u64(path.c_str()); | |
ad6bca0e RG |
48 | return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr)); |
49 | } | |
50 | ||
38b10979 | 51 | static int bpf_load_pinned_map(const std::string& path) |
ad6bca0e RG |
52 | { |
53 | union bpf_attr attr; | |
54 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 55 | attr.pathname = ptr_to_u64(path.c_str()); |
ad6bca0e RG |
56 | return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); |
57 | } | |
58 | ||
4a94ee50 | 59 | static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize) |
ad6bca0e RG |
60 | { |
61 | struct bpf_map_info info; | |
62 | uint32_t info_len = sizeof(info); | |
63 | memset(&info, 0, sizeof(info)); | |
64 | ||
65 | union bpf_attr attr; | |
66 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 67 | attr.info.bpf_fd = descriptor; |
ad6bca0e RG |
68 | attr.info.info_len = info_len; |
69 | attr.info.info = ptr_to_u64(&info); | |
70 | ||
71 | int err = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr)); | |
72 | if (err != 0) { | |
73 | throw std::runtime_error("Error checking the size of eBPF map: " + stringerror()); | |
74 | } | |
75 | if (info_len != sizeof(info)) { | |
76 | throw std::runtime_error("Error checking the size of eBPF map: invalid info size returned"); | |
77 | } | |
78 | if (info.key_size != expectedKeySize) { | |
79 | throw std::runtime_error("Error checking the size of eBPF map: key size mismatch (" + std::to_string(info.key_size) + " VS " + std::to_string(expectedKeySize) + ")"); | |
80 | } | |
81 | if (info.value_size != expectedValueSize) { | |
82 | throw std::runtime_error("Error checking the size of eBPF map: value size mismatch (" + std::to_string(info.value_size) + " VS " + std::to_string(expectedValueSize) + ")"); | |
83 | } | |
ad6bca0e RG |
84 | } |
85 | ||
94e3db7e | 86 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) |
4a94ee50 RG |
87 | static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, |
88 | int max_entries, int map_flags) | |
38b10979 RG |
89 | { |
90 | union bpf_attr attr; | |
91 | memset(&attr, 0, sizeof(attr)); | |
92 | attr.map_type = map_type; | |
93 | attr.key_size = key_size; | |
94 | attr.value_size = value_size; | |
95 | attr.max_entries = max_entries; | |
becba800 | 96 | attr.map_flags = map_flags; |
38b10979 RG |
97 | return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); |
98 | } | |
99 | ||
4a94ee50 | 100 | static int bpf_update_elem(int descriptor, void *key, void *value, unsigned long long flags) |
87b515ed | 101 | { |
eace2c24 RG |
102 | union bpf_attr attr; |
103 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 104 | attr.map_fd = descriptor; |
87b515ed RG |
105 | attr.key = ptr_to_u64(key); |
106 | attr.value = ptr_to_u64(value); | |
107 | attr.flags = flags; | |
108 | return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); | |
109 | } | |
110 | ||
4a94ee50 | 111 | static int bpf_lookup_elem(int descriptor, void *key, void *value) |
87b515ed | 112 | { |
eace2c24 RG |
113 | union bpf_attr attr; |
114 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 115 | attr.map_fd = descriptor; |
87b515ed RG |
116 | attr.key = ptr_to_u64(key); |
117 | attr.value = ptr_to_u64(value); | |
118 | return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); | |
119 | } | |
120 | ||
4a94ee50 | 121 | static int bpf_delete_elem(int descriptor, void *key) |
87b515ed | 122 | { |
eace2c24 RG |
123 | union bpf_attr attr; |
124 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 125 | attr.map_fd = descriptor; |
87b515ed RG |
126 | attr.key = ptr_to_u64(key); |
127 | return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr)); | |
128 | } | |
129 | ||
4a94ee50 | 130 | static int bpf_get_next_key(int descriptor, void *key, void *next_key) |
87b515ed | 131 | { |
eace2c24 RG |
132 | union bpf_attr attr; |
133 | memset(&attr, 0, sizeof(attr)); | |
4a94ee50 | 134 | attr.map_fd = descriptor; |
87b515ed RG |
135 | attr.key = ptr_to_u64(key); |
136 | attr.next_key = ptr_to_u64(next_key); | |
137 | return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); | |
138 | } | |
139 | ||
4a94ee50 | 140 | static int bpf_prog_load(enum bpf_prog_type prog_type, |
94e3db7e | 141 | const struct bpf_insn *insns, size_t prog_len, |
4a94ee50 | 142 | const char *license, int kern_version) |
87b515ed RG |
143 | { |
144 | char log_buf[65535]; | |
eace2c24 RG |
145 | union bpf_attr attr; |
146 | memset(&attr, 0, sizeof(attr)); | |
87b515ed RG |
147 | attr.prog_type = prog_type; |
148 | attr.insns = ptr_to_u64((void *) insns); | |
94e3db7e | 149 | attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn)); |
87b515ed RG |
150 | attr.license = ptr_to_u64((void *) license); |
151 | attr.log_buf = ptr_to_u64(log_buf); | |
152 | attr.log_size = sizeof(log_buf); | |
153 | attr.log_level = 1; | |
154 | /* assign one field outside of struct init to make sure any | |
155 | * padding is zero initialized | |
156 | */ | |
157 | attr.kern_version = kern_version; | |
158 | ||
159 | long res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | |
160 | if (res == -1) { | |
161 | if (errno == ENOSPC) { | |
162 | /* not enough space in the log buffer */ | |
163 | attr.log_level = 0; | |
164 | attr.log_size = 0; | |
165 | attr.log_buf = ptr_to_u64(nullptr); | |
166 | res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | |
167 | if (res != -1) { | |
168 | return res; | |
169 | } | |
170 | } | |
a2a81d42 | 171 | throw std::runtime_error("Error loading BPF program: (" + stringerror() + "):\n" + std::string(log_buf)); |
87b515ed RG |
172 | } |
173 | return res; | |
174 | } | |
175 | ||
176 | struct KeyV6 | |
177 | { | |
178 | uint8_t src[16]; | |
179 | }; | |
180 | ||
181 | struct QNameKey | |
182 | { | |
183 | uint8_t qname[255]; | |
184 | }; | |
185 | ||
053a020a | 186 | struct QNameAndQTypeKey |
87b515ed | 187 | { |
053a020a | 188 | uint8_t qname[255]; |
87b515ed RG |
189 | uint16_t qtype; |
190 | }; | |
191 | ||
053a020a RG |
192 | struct QNameValue |
193 | { | |
194 | uint64_t counter{0}; | |
195 | uint16_t qtype{0}; | |
196 | }; | |
197 | ||
053a020a RG |
198 | |
199 | BPFFilter::Map::Map(const BPFFilter::MapConfiguration& config, BPFFilter::MapFormat format): d_config(config) | |
87b515ed | 200 | { |
ad6bca0e RG |
201 | if (d_config.d_type == BPFFilter::MapType::Filters) { |
202 | /* special case, this is a map of eBPF programs */ | |
becba800 | 203 | d_fd = FDWrapper(bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), d_config.d_maxItems, 0)); |
ad6bca0e RG |
204 | if (d_fd.getHandle() == -1) { |
205 | throw std::runtime_error("Error creating a BPF program map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror()); | |
206 | } | |
87b515ed | 207 | } |
ad6bca0e RG |
208 | else { |
209 | int keySize = 0; | |
210 | int valueSize = 0; | |
becba800 Y |
211 | int flags = 0; |
212 | bpf_map_type type = BPF_MAP_TYPE_HASH; | |
053a020a RG |
213 | if (format == MapFormat::Legacy) { |
214 | switch (d_config.d_type) { | |
215 | case MapType::IPv4: | |
216 | keySize = sizeof(uint32_t); | |
217 | valueSize = sizeof(uint64_t); | |
218 | break; | |
219 | case MapType::IPv6: | |
220 | keySize = sizeof(KeyV6); | |
221 | valueSize = sizeof(uint64_t); | |
222 | break; | |
223 | case MapType::QNames: | |
224 | keySize = sizeof(QNameKey); | |
225 | valueSize = sizeof(QNameValue); | |
226 | break; | |
227 | default: | |
2030c200 | 228 | throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)) + " for legacy eBPF, perhaps you are trying to use an external program instead?"); |
053a020a RG |
229 | } |
230 | } | |
231 | else { | |
232 | switch (d_config.d_type) { | |
233 | case MapType::IPv4: | |
234 | keySize = sizeof(uint32_t); | |
235 | valueSize = sizeof(CounterAndActionValue); | |
236 | break; | |
237 | case MapType::IPv6: | |
238 | keySize = sizeof(KeyV6); | |
239 | valueSize = sizeof(CounterAndActionValue); | |
240 | break; | |
becba800 Y |
241 | case MapType::CIDR4: |
242 | keySize = sizeof(CIDR4); | |
243 | valueSize = sizeof(CounterAndActionValue); | |
244 | flags = BPF_F_NO_PREALLOC; | |
245 | type = BPF_MAP_TYPE_LPM_TRIE; | |
246 | break; | |
247 | case MapType::CIDR6: | |
248 | keySize = sizeof(CIDR6); | |
249 | valueSize = sizeof(CounterAndActionValue); | |
250 | flags = BPF_F_NO_PREALLOC; | |
251 | type = BPF_MAP_TYPE_LPM_TRIE; | |
252 | break; | |
053a020a RG |
253 | case MapType::QNames: |
254 | keySize = sizeof(QNameAndQTypeKey); | |
255 | valueSize = sizeof(CounterAndActionValue); | |
256 | break; | |
257 | default: | |
258 | throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type))); | |
259 | } | |
ad6bca0e | 260 | } |
87b515ed | 261 | |
ad6bca0e RG |
262 | if (!d_config.d_pinnedPath.empty()) { |
263 | /* try to load */ | |
264 | d_fd = FDWrapper(bpf_load_pinned_map(d_config.d_pinnedPath)); | |
265 | if (d_fd.getHandle() != -1) { | |
266 | /* sanity checks: key and value size */ | |
267 | bpf_check_map_sizes(d_fd.getHandle(), keySize, valueSize); | |
becba800 Y |
268 | switch (d_config.d_type) { |
269 | case MapType::IPv4: { | |
ad6bca0e | 270 | uint32_t key = 0; |
a918f0cf | 271 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { |
ad6bca0e | 272 | ++d_count; |
ad6bca0e | 273 | } |
7c06007f Y |
274 | break; |
275 | } | |
becba800 | 276 | case MapType::IPv6: { |
ad6bca0e RG |
277 | KeyV6 key; |
278 | memset(&key, 0, sizeof(key)); | |
a918f0cf | 279 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { |
ad6bca0e | 280 | ++d_count; |
ad6bca0e | 281 | } |
7c06007f Y |
282 | break; |
283 | } | |
becba800 Y |
284 | case MapType::CIDR4: { |
285 | CIDR4 key; | |
286 | memset(&key, 0, sizeof(key)); | |
287 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { | |
288 | ++d_count; | |
289 | } | |
7c06007f Y |
290 | break; |
291 | } | |
becba800 Y |
292 | case MapType::CIDR6: { |
293 | CIDR6 key; | |
294 | memset(&key, 0, sizeof(key)); | |
295 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { | |
296 | ++d_count; | |
297 | } | |
7c06007f Y |
298 | break; |
299 | } | |
becba800 | 300 | case MapType::QNames: { |
053a020a RG |
301 | if (format == MapFormat::Legacy) { |
302 | QNameKey key; | |
303 | memset(&key, 0, sizeof(key)); | |
a918f0cf | 304 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { |
053a020a | 305 | ++d_count; |
053a020a RG |
306 | } |
307 | } | |
308 | else { | |
309 | QNameAndQTypeKey key; | |
310 | memset(&key, 0, sizeof(key)); | |
a918f0cf | 311 | while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) { |
053a020a | 312 | ++d_count; |
053a020a | 313 | } |
ad6bca0e | 314 | } |
7c06007f Y |
315 | break; |
316 | } | |
becba800 Y |
317 | |
318 | default: | |
319 | throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type))); | |
ad6bca0e RG |
320 | } |
321 | } | |
322 | } | |
323 | ||
324 | if (d_fd.getHandle() == -1) { | |
becba800 | 325 | d_fd = FDWrapper(bpf_create_map(type, keySize, valueSize, static_cast<int>(d_config.d_maxItems), flags)); |
ad6bca0e RG |
326 | if (d_fd.getHandle() == -1) { |
327 | throw std::runtime_error("Error creating a BPF map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror()); | |
328 | } | |
87b515ed | 329 | |
ad6bca0e RG |
330 | if (!d_config.d_pinnedPath.empty()) { |
331 | if (bpf_pin_map(d_fd.getHandle(), d_config.d_pinnedPath) != 0) { | |
332 | throw std::runtime_error("Unable to pin map to path '" + d_config.d_pinnedPath + "': " + stringerror()); | |
333 | } | |
334 | } | |
335 | } | |
87b515ed | 336 | } |
ad6bca0e | 337 | } |
87b515ed | 338 | |
ad6bca0e RG |
339 | static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize) |
340 | { | |
4a94ee50 RG |
341 | auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, |
342 | filter, | |
343 | filterSize, | |
344 | "GPL", | |
345 | 0)); | |
346 | if (descriptor.getHandle() == -1) { | |
ad6bca0e | 347 | throw std::runtime_error("error loading BPF filter: " + stringerror()); |
87b515ed | 348 | } |
4a94ee50 | 349 | return descriptor; |
ad6bca0e RG |
350 | } |
351 | ||
352 | ||
411dccdb Y |
353 | BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) : |
354 | d_mapFormat(format), d_external(external) | |
ad6bca0e | 355 | { |
053a020a RG |
356 | if (d_mapFormat != BPFFilter::MapFormat::Legacy && !d_external) { |
357 | throw std::runtime_error("Unsupported eBPF map format, the current internal implemenation only supports the legacy format"); | |
358 | } | |
359 | ||
dc22be50 | 360 | struct rlimit old_limit; |
dc22be50 YS |
361 | if (getrlimit(RLIMIT_MEMLOCK, &old_limit) != 0) { |
362 | throw std::runtime_error("Unable to get memory lock limit: " + stringerror()); | |
363 | } | |
364 | ||
ad979582 OM |
365 | const rlim_t new_limit_size = 1024 * 1024; |
366 | ||
7b6e1bb8 OM |
367 | /* Check if the current soft memlock limit is at least the limit */ |
368 | if (old_limit.rlim_cur < new_limit_size) { | |
ad979582 OM |
369 | infolog("The current limit of locked memory (soft: %d, hard: %d) is too low for eBPF, trying to raise it to %d", old_limit.rlim_cur, old_limit.rlim_max, new_limit_size); |
370 | ||
dc22be50 | 371 | struct rlimit new_limit; |
ad979582 OM |
372 | new_limit.rlim_cur = new_limit_size; |
373 | new_limit.rlim_max = new_limit_size; | |
374 | ||
dc22be50 | 375 | if (setrlimit(RLIMIT_MEMLOCK, &new_limit) != 0) { |
ad979582 | 376 | warnlog("Unable to raise the maximum amount of locked memory for eBPF from %d to %d, consider raising RLIMIT_MEMLOCK or setting LimitMEMLOCK in the systemd unit: %d", old_limit.rlim_cur, new_limit.rlim_cur, stringerror()); |
dc22be50 | 377 | } |
dc22be50 YS |
378 | } |
379 | ||
ad6bca0e | 380 | auto maps = d_maps.lock(); |
87b515ed | 381 | |
fc8ce347 Y |
382 | maps->d_v4 = BPFFilter::Map(configs["ipv4"], d_mapFormat); |
383 | maps->d_v6 = BPFFilter::Map(configs["ipv6"], d_mapFormat); | |
384 | maps->d_qnames = BPFFilter::Map(configs["qnames"], d_mapFormat); | |
2030c200 Y |
385 | |
386 | if (d_mapFormat != BPFFilter::MapFormat::Legacy) { | |
387 | maps->d_cidr4 = BPFFilter::Map(configs["cidr4"], d_mapFormat); | |
388 | maps->d_cidr6 = BPFFilter::Map(configs["cidr6"], d_mapFormat); | |
389 | } | |
390 | ||
053a020a RG |
391 | if (!external) { |
392 | BPFFilter::MapConfiguration filters; | |
393 | filters.d_maxItems = 1; | |
394 | filters.d_type = BPFFilter::MapType::Filters; | |
395 | maps->d_filters = BPFFilter::Map(filters, d_mapFormat); | |
ad6bca0e | 396 | |
053a020a | 397 | const struct bpf_insn main_filter[] = { |
d45189b7 | 398 | #include "bpf-filter.main.ebpf" |
053a020a | 399 | }; |
d45189b7 | 400 | |
053a020a | 401 | const struct bpf_insn qname_filter[] = { |
d45189b7 | 402 | #include "bpf-filter.qname.ebpf" |
053a020a | 403 | }; |
d45189b7 | 404 | |
053a020a RG |
405 | try { |
406 | d_mainfilter = loadProgram(main_filter, | |
407 | sizeof(main_filter)); | |
408 | } | |
409 | catch (const std::exception& e) { | |
410 | throw std::runtime_error("Error load the main eBPF filter: " + std::string(e.what())); | |
411 | } | |
ad6bca0e | 412 | |
053a020a RG |
413 | try { |
414 | d_qnamefilter = loadProgram(qname_filter, | |
415 | sizeof(qname_filter)); | |
416 | } | |
417 | catch (const std::exception& e) { | |
418 | throw std::runtime_error("Error load the qname eBPF filter: " + std::string(e.what())); | |
419 | } | |
d45189b7 | 420 | |
053a020a RG |
421 | uint32_t key = 0; |
422 | int qnamefd = d_qnamefilter.getHandle(); | |
423 | int res = bpf_update_elem(maps->d_filters.d_fd.getHandle(), &key, &qnamefd, BPF_ANY); | |
424 | if (res != 0) { | |
425 | throw std::runtime_error("Error updating BPF filters map: " + stringerror()); | |
426 | } | |
87b515ed RG |
427 | } |
428 | } | |
429 | ||
430 | void BPFFilter::addSocket(int sock) | |
431 | { | |
4a94ee50 RG |
432 | int descriptor = d_mainfilter.getHandle(); |
433 | int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor)); | |
87b515ed RG |
434 | |
435 | if (res != 0) { | |
a2a81d42 | 436 | throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror()); |
87b515ed RG |
437 | } |
438 | } | |
439 | ||
8429ad04 RG |
440 | void BPFFilter::removeSocket(int sock) |
441 | { | |
4a94ee50 RG |
442 | int descriptor = d_mainfilter.getHandle(); |
443 | int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor)); | |
8429ad04 RG |
444 | |
445 | if (res != 0) { | |
a2a81d42 | 446 | throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror()); |
8429ad04 RG |
447 | } |
448 | } | |
449 | ||
053a020a | 450 | void BPFFilter::block(const ComboAddress& addr, BPFFilter::MatchAction action) |
87b515ed | 451 | { |
053a020a RG |
452 | CounterAndActionValue value; |
453 | value.counter = 0; | |
454 | value.action = action; | |
455 | ||
87b515ed | 456 | int res = 0; |
0da9ec8d | 457 | if (addr.isIPv4()) { |
87b515ed | 458 | uint32_t key = htonl(addr.sin4.sin_addr.s_addr); |
f0114d6b | 459 | auto maps = d_maps.lock(); |
ad6bca0e RG |
460 | auto& map = maps->d_v4; |
461 | if (map.d_count >= map.d_config.d_maxItems) { | |
87b515ed RG |
462 | throw std::runtime_error("Table full when trying to block " + addr.toString()); |
463 | } | |
464 | ||
053a020a | 465 | res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value); |
87b515ed RG |
466 | if (res != -1) { |
467 | throw std::runtime_error("Trying to block an already blocked address: " + addr.toString()); | |
468 | } | |
469 | ||
053a020a | 470 | res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST); |
87b515ed | 471 | if (res == 0) { |
ad6bca0e | 472 | ++map.d_count; |
87b515ed RG |
473 | } |
474 | } | |
0da9ec8d | 475 | else if (addr.isIPv6()) { |
87b515ed RG |
476 | uint8_t key[16]; |
477 | static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t"); | |
478 | for (size_t idx = 0; idx < sizeof(key); idx++) { | |
479 | key[idx] = addr.sin6.sin6_addr.s6_addr[idx]; | |
480 | } | |
481 | ||
f0114d6b | 482 | auto maps = d_maps.lock(); |
ad6bca0e RG |
483 | auto& map = maps->d_v6; |
484 | if (map.d_count >= map.d_config.d_maxItems) { | |
87b515ed RG |
485 | throw std::runtime_error("Table full when trying to block " + addr.toString()); |
486 | } | |
487 | ||
053a020a | 488 | res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value); |
87b515ed RG |
489 | if (res != -1) { |
490 | throw std::runtime_error("Trying to block an already blocked address: " + addr.toString()); | |
491 | } | |
492 | ||
053a020a | 493 | res = bpf_update_elem(map.d_fd.getHandle(), key, &value, BPF_NOEXIST); |
87b515ed | 494 | if (res == 0) { |
ad6bca0e | 495 | map.d_count++; |
87b515ed RG |
496 | } |
497 | } | |
498 | ||
499 | if (res != 0) { | |
a2a81d42 | 500 | throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror()); |
87b515ed RG |
501 | } |
502 | } | |
503 | ||
504 | void BPFFilter::unblock(const ComboAddress& addr) | |
505 | { | |
87b515ed | 506 | int res = 0; |
0da9ec8d | 507 | if (addr.isIPv4()) { |
87b515ed | 508 | uint32_t key = htonl(addr.sin4.sin_addr.s_addr); |
f0114d6b | 509 | auto maps = d_maps.lock(); |
ad6bca0e RG |
510 | auto& map = maps->d_v4; |
511 | res = bpf_delete_elem(map.d_fd.getHandle(), &key); | |
87b515ed | 512 | if (res == 0) { |
ad6bca0e | 513 | --map.d_count; |
87b515ed RG |
514 | } |
515 | } | |
0da9ec8d | 516 | else if (addr.isIPv6()) { |
87b515ed RG |
517 | uint8_t key[16]; |
518 | static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t"); | |
519 | for (size_t idx = 0; idx < sizeof(key); idx++) { | |
520 | key[idx] = addr.sin6.sin6_addr.s6_addr[idx]; | |
521 | } | |
522 | ||
f0114d6b | 523 | auto maps = d_maps.lock(); |
ad6bca0e RG |
524 | auto& map = maps->d_v6; |
525 | res = bpf_delete_elem(map.d_fd.getHandle(), key); | |
87b515ed | 526 | if (res == 0) { |
ad6bca0e | 527 | --map.d_count; |
87b515ed RG |
528 | } |
529 | } | |
530 | ||
531 | if (res != 0) { | |
a2a81d42 | 532 | throw std::runtime_error("Error removing blocked address " + addr.toString() + ": " + stringerror()); |
87b515ed RG |
533 | } |
534 | } | |
535 | ||
b31a0ea8 | 536 | void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action) |
becba800 Y |
537 | { |
538 | CounterAndActionValue value; | |
539 | ||
540 | int res = 0; | |
541 | if (addr.isIPv4()) { | |
542 | CIDR4 key(addr); | |
543 | auto maps = d_maps.lock(); | |
544 | auto& map = maps->d_cidr4; | |
2030c200 Y |
545 | if (map.d_fd.getHandle() == -1) { |
546 | throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program"); | |
547 | } | |
becba800 | 548 | if (map.d_count >= map.d_config.d_maxItems) { |
b31a0ea8 | 549 | throw std::runtime_error("Table full when trying to add this rule: " + addr.toString()); |
becba800 Y |
550 | } |
551 | ||
552 | res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value); | |
b31a0ea8 Y |
553 | if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) { |
554 | throw std::runtime_error("Trying to add a useless rule: " + addr.toString()); | |
becba800 Y |
555 | } |
556 | ||
557 | value.counter = 0; | |
558 | value.action = action; | |
559 | ||
b1419e5e | 560 | res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, force ? BPF_ANY : BPF_NOEXIST); |
becba800 Y |
561 | if (res == 0) { |
562 | ++map.d_count; | |
563 | } | |
564 | } | |
565 | else if (addr.isIPv6()) { | |
566 | CIDR6 key(addr); | |
567 | ||
568 | auto maps = d_maps.lock(); | |
569 | auto& map = maps->d_cidr6; | |
2030c200 Y |
570 | if (map.d_fd.getHandle() == -1) { |
571 | throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program"); | |
572 | } | |
becba800 | 573 | if (map.d_count >= map.d_config.d_maxItems) { |
b31a0ea8 | 574 | throw std::runtime_error("Table full when trying to add this rule: " + addr.toString()); |
becba800 Y |
575 | } |
576 | ||
577 | res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value); | |
b31a0ea8 Y |
578 | if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) { |
579 | throw std::runtime_error("Trying to add a useless rule: " + addr.toString()); | |
becba800 Y |
580 | } |
581 | ||
582 | value.counter = 0; | |
583 | value.action = action; | |
584 | ||
585 | res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST); | |
586 | if (res == 0) { | |
587 | map.d_count++; | |
588 | } | |
589 | } | |
590 | ||
591 | if (res != 0) { | |
b31a0ea8 | 592 | throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror()); |
becba800 Y |
593 | } |
594 | } | |
595 | ||
b31a0ea8 | 596 | void BPFFilter::rmRangeRule(const Netmask& addr) |
becba800 Y |
597 | { |
598 | int res = 0; | |
599 | CounterAndActionValue value; | |
600 | value.counter = 0; | |
601 | value.action = MatchAction::Pass; | |
602 | if (addr.isIPv4()) { | |
603 | CIDR4 key(addr); | |
604 | auto maps = d_maps.lock(); | |
605 | auto& map = maps->d_cidr4; | |
2030c200 Y |
606 | if (map.d_fd.getHandle() == -1) { |
607 | throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program"); | |
608 | } | |
becba800 Y |
609 | res = bpf_delete_elem(map.d_fd.getHandle(), &key); |
610 | if (res == 0) { | |
611 | --map.d_count; | |
612 | } | |
613 | else { | |
b31a0ea8 | 614 | throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule"); |
becba800 Y |
615 | } |
616 | } | |
617 | else if (addr.isIPv6()) { | |
618 | CIDR6 key(addr); | |
619 | ||
620 | auto maps = d_maps.lock(); | |
621 | auto& map = maps->d_cidr6; | |
2030c200 Y |
622 | if (map.d_fd.getHandle() == -1) { |
623 | throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program"); | |
624 | } | |
becba800 Y |
625 | res = bpf_delete_elem(map.d_fd.getHandle(), &key); |
626 | if (res == 0) { | |
627 | --map.d_count; | |
628 | } | |
629 | else { | |
b31a0ea8 | 630 | throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule"); |
becba800 Y |
631 | } |
632 | } | |
633 | ||
634 | if (res != 0) { | |
b31a0ea8 | 635 | throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror()); |
becba800 Y |
636 | } |
637 | } | |
638 | ||
053a020a | 639 | void BPFFilter::block(const DNSName& qname, BPFFilter::MatchAction action, uint16_t qtype) |
87b515ed | 640 | { |
053a020a RG |
641 | CounterAndActionValue cadvalue; |
642 | QNameValue qvalue; | |
643 | void* value = nullptr; | |
644 | ||
645 | if (d_external) { | |
053a020a RG |
646 | cadvalue.counter = 0; |
647 | cadvalue.action = action; | |
648 | value = &cadvalue; | |
649 | } | |
650 | else { | |
053a020a RG |
651 | qvalue.counter = 0; |
652 | qvalue.qtype = qtype; | |
653 | value = &qvalue; | |
654 | } | |
655 | ||
656 | QNameAndQTypeKey key; | |
87b515ed | 657 | memset(&key, 0, sizeof(key)); |
87b515ed | 658 | |
d45189b7 | 659 | std::string keyStr = qname.toDNSStringLC(); |
87b515ed | 660 | if (keyStr.size() > sizeof(key.qname)) { |
86f1af1c | 661 | throw std::runtime_error("Invalid QName to block " + qname.toLogString()); |
87b515ed RG |
662 | } |
663 | memcpy(key.qname, keyStr.c_str(), keyStr.size()); | |
053a020a | 664 | key.qtype = qtype; |
87b515ed RG |
665 | |
666 | { | |
f0114d6b | 667 | auto maps = d_maps.lock(); |
ad6bca0e RG |
668 | auto& map = maps->d_qnames; |
669 | if (map.d_count >= map.d_config.d_maxItems) { | |
86f1af1c | 670 | throw std::runtime_error("Table full when trying to block " + qname.toLogString()); |
87b515ed RG |
671 | } |
672 | ||
815aee7a | 673 | int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, value); |
87b515ed | 674 | if (res != -1) { |
86f1af1c | 675 | throw std::runtime_error("Trying to block an already blocked qname: " + qname.toLogString()); |
87b515ed | 676 | } |
815aee7a | 677 | res = bpf_update_elem(map.d_fd.getHandle(), &key, value, BPF_NOEXIST); |
87b515ed | 678 | if (res == 0) { |
ad6bca0e | 679 | ++map.d_count; |
87b515ed RG |
680 | } |
681 | ||
682 | if (res != 0) { | |
16f0c288 | 683 | throw std::runtime_error("Error adding blocked qname " + qname.toLogString() + ": " + stringerror()); |
87b515ed RG |
684 | } |
685 | } | |
686 | } | |
687 | ||
688 | void BPFFilter::unblock(const DNSName& qname, uint16_t qtype) | |
689 | { | |
053a020a RG |
690 | QNameAndQTypeKey key; |
691 | memset(&key, 0, sizeof(key)); | |
d45189b7 | 692 | std::string keyStr = qname.toDNSStringLC(); |
87b515ed RG |
693 | |
694 | if (keyStr.size() > sizeof(key.qname)) { | |
86f1af1c | 695 | throw std::runtime_error("Invalid QName to block " + qname.toLogString()); |
87b515ed RG |
696 | } |
697 | memcpy(key.qname, keyStr.c_str(), keyStr.size()); | |
053a020a | 698 | key.qtype = qtype; |
87b515ed RG |
699 | |
700 | { | |
f0114d6b | 701 | auto maps = d_maps.lock(); |
ad6bca0e RG |
702 | auto& map = maps->d_qnames; |
703 | int res = bpf_delete_elem(map.d_fd.getHandle(), &key); | |
87b515ed | 704 | if (res == 0) { |
ad6bca0e | 705 | --map.d_count; |
87b515ed RG |
706 | } |
707 | else { | |
16f0c288 | 708 | throw std::runtime_error("Error removing qname address " + qname.toLogString() + ": " + stringerror()); |
87b515ed RG |
709 | } |
710 | } | |
711 | } | |
712 | ||
713 | std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats() | |
714 | { | |
715 | std::vector<std::pair<ComboAddress, uint64_t> > result; | |
f0114d6b RG |
716 | { |
717 | auto maps = d_maps.lock(); | |
ad6bca0e | 718 | result.reserve(maps->d_v4.d_count + maps->d_v6.d_count); |
f0114d6b | 719 | } |
87b515ed | 720 | |
d26d9f52 | 721 | sockaddr_in v4Addr{}; |
eace2c24 | 722 | memset(&v4Addr, 0, sizeof(v4Addr)); |
87b515ed RG |
723 | v4Addr.sin_family = AF_INET; |
724 | ||
0da9ec8d | 725 | uint32_t v4Key = 0; |
d26d9f52 RG |
726 | uint32_t nextV4Key{}; |
727 | CounterAndActionValue value{}; | |
87b515ed | 728 | |
d26d9f52 RG |
729 | std::array<uint8_t, 16> v6Key{}; |
730 | std::array<uint8_t, 16> nextV6Key{}; | |
731 | sockaddr_in6 v6Addr{}; | |
eace2c24 | 732 | memset(&v6Addr, 0, sizeof(v6Addr)); |
87b515ed | 733 | v6Addr.sin6_family = AF_INET6; |
eace2c24 | 734 | |
d26d9f52 | 735 | static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t"); |
c3186616 | 736 | memset(&v6Key, 0, sizeof(v6Key)); |
87b515ed | 737 | |
f0114d6b | 738 | auto maps = d_maps.lock(); |
0da9ec8d | 739 | |
ad6bca0e RG |
740 | { |
741 | auto& map = maps->d_v4; | |
742 | int res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key); | |
743 | ||
744 | while (res == 0) { | |
745 | v4Key = nextV4Key; | |
746 | if (bpf_lookup_elem(map.d_fd.getHandle(), &v4Key, &value) == 0) { | |
0da9ec8d | 747 | v4Addr.sin_addr.s_addr = ntohl(v4Key); |
053a020a | 748 | result.emplace_back(ComboAddress(&v4Addr), value.counter); |
ad6bca0e | 749 | } |
0da9ec8d | 750 | |
ad6bca0e RG |
751 | res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key); |
752 | } | |
0da9ec8d RG |
753 | } |
754 | ||
ad6bca0e RG |
755 | { |
756 | auto& map = maps->d_v6; | |
d26d9f52 | 757 | int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data()); |
87b515ed | 758 | |
ad6bca0e | 759 | while (res == 0) { |
d26d9f52 RG |
760 | if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) { |
761 | memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size()); | |
c3186616 | 762 | |
053a020a | 763 | result.emplace_back(ComboAddress(&v6Addr), value.counter); |
ad6bca0e | 764 | } |
87b515ed | 765 | |
d26d9f52 | 766 | res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data()); |
ad6bca0e | 767 | } |
87b515ed | 768 | } |
ad6bca0e | 769 | |
87b515ed RG |
770 | return result; |
771 | } | |
772 | ||
b31a0ea8 | 773 | std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule() |
783b8632 Y |
774 | { |
775 | CIDR4 cidr4[2]; | |
776 | CIDR6 cidr6[2]; | |
b31a0ea8 | 777 | std::vector<std::pair<Netmask, CounterAndActionValue>> result; |
783b8632 Y |
778 | |
779 | sockaddr_in v4Addr; | |
780 | sockaddr_in6 v6Addr; | |
781 | CounterAndActionValue value; | |
782 | ||
783 | memset(cidr4, 0, sizeof(cidr4)); | |
784 | memset(cidr6, 0, sizeof(cidr6)); | |
785 | memset(&v4Addr, 0, sizeof(v4Addr)); | |
786 | memset(&v6Addr, 0, sizeof(v6Addr)); | |
3930c0e7 Y |
787 | v4Addr.sin_family = AF_INET; |
788 | v6Addr.sin6_family = AF_INET6; | |
783b8632 Y |
789 | auto maps = d_maps.lock(); |
790 | result.reserve(maps->d_cidr4.d_count + maps->d_cidr6.d_count); | |
791 | { | |
792 | auto& map = maps->d_cidr4; | |
793 | int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[0], &cidr4[1]); | |
794 | while (res == 0) { | |
795 | if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) { | |
796 | v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr; | |
b31a0ea8 | 797 | result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value); |
783b8632 Y |
798 | } |
799 | ||
800 | res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]); | |
801 | } | |
802 | } | |
803 | ||
804 | { | |
805 | auto& map = maps->d_cidr6; | |
806 | int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[0], &cidr6[1]); | |
807 | while (res == 0) { | |
808 | if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) { | |
11cf516b | 809 | v6Addr.sin6_addr = cidr6[1].addr; |
b31a0ea8 | 810 | result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value); |
783b8632 Y |
811 | } |
812 | ||
813 | res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]); | |
814 | } | |
815 | } | |
816 | return result; | |
817 | } | |
818 | ||
87b515ed RG |
819 | std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats() |
820 | { | |
821 | std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result; | |
87b515ed | 822 | |
053a020a RG |
823 | if (d_mapFormat == MapFormat::Legacy) { |
824 | QNameKey key = { { 0 } }; | |
825 | QNameKey nextKey = { { 0 } }; | |
826 | QNameValue value; | |
87b515ed | 827 | |
053a020a RG |
828 | auto maps = d_maps.lock(); |
829 | auto& map = maps->d_qnames; | |
830 | result.reserve(map.d_count); | |
831 | int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey); | |
87b515ed | 832 | |
053a020a RG |
833 | while (res == 0) { |
834 | if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) { | |
835 | nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0'; | |
0b0882f5 | 836 | result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter); |
053a020a RG |
837 | } |
838 | ||
839 | res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey); | |
87b515ed | 840 | } |
053a020a RG |
841 | } |
842 | else { | |
843 | QNameAndQTypeKey key; | |
844 | QNameAndQTypeKey nextKey; | |
845 | memset(&key, 0, sizeof(key)); | |
846 | memset(&nextKey, 0, sizeof(nextKey)); | |
847 | CounterAndActionValue value; | |
848 | ||
849 | auto maps = d_maps.lock(); | |
850 | auto& map = maps->d_qnames; | |
851 | result.reserve(map.d_count); | |
852 | int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey); | |
87b515ed | 853 | |
053a020a RG |
854 | while (res == 0) { |
855 | if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) { | |
856 | nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0'; | |
0b0882f5 | 857 | result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter); |
053a020a RG |
858 | } |
859 | ||
860 | res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey); | |
861 | } | |
87b515ed | 862 | } |
053a020a | 863 | |
87b515ed RG |
864 | return result; |
865 | } | |
0da9ec8d RG |
866 | |
867 | uint64_t BPFFilter::getHits(const ComboAddress& requestor) | |
868 | { | |
053a020a RG |
869 | CounterAndActionValue counter; |
870 | ||
0da9ec8d RG |
871 | if (requestor.isIPv4()) { |
872 | uint32_t key = htonl(requestor.sin4.sin_addr.s_addr); | |
873 | ||
f0114d6b | 874 | auto maps = d_maps.lock(); |
ad6bca0e RG |
875 | auto& map = maps->d_v4; |
876 | int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter); | |
0da9ec8d | 877 | if (res == 0) { |
053a020a | 878 | return counter.counter; |
0da9ec8d RG |
879 | } |
880 | } | |
881 | else if (requestor.isIPv6()) { | |
882 | uint8_t key[16]; | |
883 | static_assert(sizeof(requestor.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t"); | |
884 | for (size_t idx = 0; idx < sizeof(key); idx++) { | |
885 | key[idx] = requestor.sin6.sin6_addr.s6_addr[idx]; | |
886 | } | |
887 | ||
f0114d6b | 888 | auto maps = d_maps.lock(); |
ad6bca0e RG |
889 | auto& map = maps->d_v6; |
890 | int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter); | |
0da9ec8d | 891 | if (res == 0) { |
053a020a | 892 | return counter.counter; |
0da9ec8d RG |
893 | } |
894 | } | |
895 | ||
896 | return 0; | |
897 | } | |
898 | ||
899 | #else | |
900 | ||
411dccdb | 901 | BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) |
0da9ec8d RG |
902 | { |
903 | } | |
904 | ||
ad6bca0e | 905 | void BPFFilter::addSocket(int) |
0da9ec8d | 906 | { |
0da9ec8d RG |
907 | throw std::runtime_error("eBPF support not enabled"); |
908 | } | |
909 | ||
ad6bca0e | 910 | void BPFFilter::removeSocket(int) |
0da9ec8d | 911 | { |
0da9ec8d RG |
912 | throw std::runtime_error("eBPF support not enabled"); |
913 | } | |
914 | ||
053a020a | 915 | void BPFFilter::block(const ComboAddress&, BPFFilter::MatchAction) |
0da9ec8d | 916 | { |
0da9ec8d RG |
917 | throw std::runtime_error("eBPF support not enabled"); |
918 | } | |
919 | ||
ad6bca0e | 920 | void BPFFilter::unblock(const ComboAddress&) |
0da9ec8d | 921 | { |
0da9ec8d RG |
922 | throw std::runtime_error("eBPF support not enabled"); |
923 | } | |
924 | ||
053a020a | 925 | void BPFFilter::block(const DNSName&, BPFFilter::MatchAction, uint16_t) |
0da9ec8d | 926 | { |
0da9ec8d RG |
927 | throw std::runtime_error("eBPF support not enabled"); |
928 | } | |
929 | ||
ad6bca0e | 930 | void BPFFilter::unblock(const DNSName&, uint16_t) |
0da9ec8d | 931 | { |
0da9ec8d RG |
932 | throw std::runtime_error("eBPF support not enabled"); |
933 | } | |
934 | ||
b31a0ea8 | 935 | void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction) |
becba800 Y |
936 | { |
937 | throw std::runtime_error("eBPF support not enabled"); | |
938 | } | |
b31a0ea8 | 939 | void BPFFilter::rmRangeRule(const Netmask&) |
becba800 Y |
940 | { |
941 | throw std::runtime_error("eBPF support not enabled"); | |
942 | } | |
943 | ||
b31a0ea8 Y |
944 | std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule(){ |
945 | std::vector<std::pair<Netmask, CounterAndActionValue>> result; | |
946 | return result; | |
947 | } | |
0da9ec8d RG |
948 | std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats() |
949 | { | |
950 | std::vector<std::pair<ComboAddress, uint64_t> > result; | |
951 | return result; | |
952 | } | |
953 | ||
954 | std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats() | |
955 | { | |
956 | std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result; | |
957 | return result; | |
958 | } | |
959 | ||
ad6bca0e | 960 | uint64_t BPFFilter::getHits(const ComboAddress&) |
0da9ec8d | 961 | { |
0da9ec8d RG |
962 | return 0; |
963 | } | |
87b515ed | 964 | #endif /* HAVE_EBPF */ |
053a020a RG |
965 | |
966 | bool BPFFilter::supportsMatchAction(MatchAction action) const | |
967 | { | |
968 | #ifdef HAVE_EBPF | |
969 | if (action == BPFFilter::MatchAction::Drop) { | |
970 | return true; | |
971 | } | |
972 | return d_mapFormat == BPFFilter::MapFormat::WithActions; | |
973 | #endif /* HAVE_EBPF */ | |
974 | return false; | |
975 | } | |
976 | ||
977 | bool BPFFilter::isExternal() const | |
978 | { | |
979 | #ifdef HAVE_EBPF | |
980 | return d_external; | |
981 | #endif /* HAVE_EBPF */ | |
982 | return false; | |
983 | } |