]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/bpf-filter.hh
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[thirdparty/pdns.git] / pdns / bpf-filter.hh
CommitLineData
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
RG
22#pragma once
23#include "config.h"
24
4a7d2cbb
OM
25#include <unordered_map>
26
87b515ed 27#include "iputils.hh"
f0114d6b 28#include "lock.hh"
becba800
Y
29#include <netinet/in.h>
30#include <stdexcept>
87b515ed 31
87b515ed
RG
32class BPFFilter
33{
34public:
ad6bca0e
RG
35 enum class MapType : uint8_t {
36 IPv4,
37 IPv6,
38 QNames,
becba800
Y
39 Filters,
40 CIDR4,
41 CIDR6
ad6bca0e
RG
42 };
43
053a020a
RG
44 enum class MapFormat : uint8_t {
45 Legacy = 0,
46 WithActions = 1
47 };
48
e1f6c2bd 49 enum class MatchAction : uint8_t {
053a020a
RG
50 Pass = 0,
51 Drop = 1,
52 Truncate = 2
53 };
b31a0ea8
Y
54 static std::string toString(MatchAction s) noexcept
55 {
56 switch (s) {
57 case MatchAction::Pass:
58 return "Pass";
59 case MatchAction::Drop:
60 return "Drop";
61 case MatchAction::Truncate:
b68b6a57 62 return "Truncate";
b31a0ea8 63 }
1f439a4c 64 return "Unknown";
b31a0ea8 65 }
053a020a 66
ad6bca0e
RG
67 struct MapConfiguration
68 {
69 std::string d_pinnedPath;
70 uint32_t d_maxItems{0};
71 MapType d_type;
72 };
73
b31a0ea8
Y
74 struct CounterAndActionValue
75 {
76 uint64_t counter{0};
77 BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
78 };
79
053a020a 80
411dccdb 81 BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
ad6bca0e
RG
82 BPFFilter(const BPFFilter&) = delete;
83 BPFFilter(BPFFilter&&) = delete;
84 BPFFilter& operator=(const BPFFilter&) = delete;
85 BPFFilter& operator=(BPFFilter&&) = delete;
86
87b515ed 87 void addSocket(int sock);
8429ad04 88 void removeSocket(int sock);
053a020a 89 void block(const ComboAddress& addr, MatchAction action);
b31a0ea8 90 void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
053a020a 91 void block(const DNSName& qname, MatchAction action, uint16_t qtype=255);
87b515ed 92 void unblock(const ComboAddress& addr);
b31a0ea8 93 void rmRangeRule(const Netmask& address);
87b515ed 94 void unblock(const DNSName& qname, uint16_t qtype=255);
ad6bca0e 95
87b515ed 96 std::vector<std::pair<ComboAddress, uint64_t> > getAddrStats();
b31a0ea8 97 std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
87b515ed 98 std::vector<std::tuple<DNSName, uint16_t, uint64_t> > getQNameStats();
ad6bca0e 99
0da9ec8d
RG
100 uint64_t getHits(const ComboAddress& requestor);
101
053a020a
RG
102 bool supportsMatchAction(MatchAction action) const;
103 bool isExternal() const;
104
87b515ed 105private:
c3186616 106#ifdef HAVE_EBPF
ad6bca0e
RG
107 struct Map
108 {
109 Map()
110 {
111 }
053a020a 112 Map(const MapConfiguration&, MapFormat);
ad6bca0e
RG
113 MapConfiguration d_config;
114 uint32_t d_count{0};
115 FDWrapper d_fd;
116 };
117
f0114d6b
RG
118 struct Maps
119 {
ad6bca0e
RG
120 Map d_v4;
121 Map d_v6;
becba800
Y
122 Map d_cidr4;
123 Map d_cidr6;
ad6bca0e
RG
124 Map d_qnames;
125 /* The qname filter program held in d_qnamefilter is
126 stored in an eBPF map, so we can call it from the
127 main filter. This is the only entry in that map. */
128 Map d_filters;
f0114d6b 129 };
ad6bca0e 130
f0114d6b 131 LockGuarded<Maps> d_maps;
ad6bca0e
RG
132
133 /* main eBPF program */
f0114d6b 134 FDWrapper d_mainfilter;
ad6bca0e 135 /* qname filtering program */
f0114d6b 136 FDWrapper d_qnamefilter;
becba800
Y
137 struct CIDR4
138 {
139 uint32_t cidr;
140 struct in_addr addr;
141 explicit CIDR4(Netmask address)
142 {
143 if (!address.isIPv4()) {
144 throw std::runtime_error("ComboAddress is invalid");
145 }
146 addr = address.getNetwork().sin4.sin_addr;
147 cidr = address.getBits();
148 }
149 CIDR4() = default;
150 };
151 struct CIDR6
152 {
153 uint32_t cidr;
154 struct in6_addr addr;
155 CIDR6(Netmask address)
156 {
f2f145aa 157 if (!address.isIPv6()) {
becba800
Y
158 throw std::runtime_error("ComboAddress is invalid");
159 }
160 addr = address.getNetwork().sin6.sin6_addr;
161 cidr = address.getBits();
162 }
163 CIDR6() = default;
164 };
053a020a
RG
165 /* whether the maps are in the 'old' format, which we need
166 to keep to prevent going over the 4k instructions per eBPF
167 program limit in kernels < 5.2, as well as the complexity limit:
168 - 32k in Linux 3.18
169 - 64k in Linux 4.7
170 - 96k in Linux 4.12
171 - 128k in Linux 4.14,
172 - 1M in Linux 5.2 */
173 MapFormat d_mapFormat;
174
175 /* whether the filter is internal, using our own eBPF programs,
176 or external where we only update the maps but the filtering is
177 done by an external program. */
178 bool d_external;
c3186616 179#endif /* HAVE_EBPF */
87b515ed 180};
5bca3433 181using CounterAndActionValue = BPFFilter::CounterAndActionValue;