]>
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 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 |
32 | class BPFFilter |
33 | { | |
34 | public: | |
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 | 105 | private: |
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 | 181 | using CounterAndActionValue = BPFFilter::CounterAndActionValue; |