]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/filterpo.hh
Merge pull request #8096 from mind04/pdns-notify-db-queries
[thirdparty/pdns.git] / pdns / filterpo.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 */
644dd1da 22#pragma once
23#include "iputils.hh"
24#include "dns.hh"
6791663c 25#include "dnsname.hh"
39ec5d29 26#include "dnsparser.hh"
644dd1da 27#include <map>
0a273054 28#include <unordered_map>
e37e5795 29#include <limits>
644dd1da 30
31/* This class implements a filtering policy that is able to fully implement RPZ, but is not bound to it.
32 In other words, it is generic enough to support RPZ, but could get its data from other places.
33
34
35 We know the following actions:
6791663c 36
644dd1da 37 No action - just pass it on
38 Drop - drop a query, no response
6791663c 39 NXDOMAIN - fake up an NXDOMAIN for the query
644dd1da 40 NODATA - just return no data for this qtype
41 Truncate - set TC bit
42 Modified - "we fake an answer for you"
43
44 These actions can be caused by the following triggers:
6791663c 45
644dd1da 46 qname - the query name
47 client-ip - the IP address of the requestor
48 response-ip - an IP address in the response
49 ns-name - the name of a server used in the delegation
50 ns-ip - the IP address of a server used in the delegation
51
52 This means we get several hook points:
53 1) when the query comes in: qname & client-ip
54 2) during processing: ns-name & ns-ip
55 3) after processing: response-ip
56
57 Triggers meanwhile can apply to:
58 Verbatim domain names
59 Wildcard versions (*.domain.com does NOT match domain.com)
60 Netmasks (IPv4 and IPv6)
644dd1da 61 Finally, triggers are grouped in different zones. The "first" zone that has a match
6791663c 62 is consulted. Then within that zone, rules again have precedences.
644dd1da 63*/
64
65
66class DNSFilterEngine
67{
68public:
e37e5795
OM
69 enum class PolicyKind : uint8_t { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
70 enum class PolicyType : uint8_t { None, QName, ClientIP, ResponseIP, NSDName, NSIP };
71 typedef uint16_t Priority;
72 static const Priority maximumPriority = std::numeric_limits<Priority>::max();
73
6da513b2
RG
74 static std::string getKindToString(PolicyKind kind);
75 static std::string getTypeToString(PolicyType type);
76
39ec5d29 77 struct Policy
78 {
e37e5795 79 Policy(): d_name(nullptr), d_ttl(0), d_priority(maximumPriority), d_kind(PolicyKind::NoAction), d_type(PolicyType::None)
1f1ca368
RG
80 {
81 }
6da513b2 82
e37e5795 83 Policy(PolicyKind kind, PolicyType type, int32_t ttl=0, std::shared_ptr<std::string> name=nullptr, const std::vector<std::shared_ptr<DNSRecordContent>>& custom={}): d_custom(custom), d_name(name), d_ttl(ttl), d_priority(maximumPriority), d_kind(kind), d_type(type)
6da513b2
RG
84 {
85 }
86
39ec5d29 87 bool operator==(const Policy& rhs) const
88 {
6da513b2 89 return d_kind == rhs.d_kind && d_type == rhs.d_type && d_ttl == rhs.d_ttl && d_custom == rhs.d_custom;
39ec5d29 90 }
6da513b2
RG
91 std::vector<DNSRecord> getCustomRecords(const DNSName& qname, uint16_t qtype) const;
92 std::vector<DNSRecord> getRecords(const DNSName& qname) const;
6791663c 93
6da513b2
RG
94 std::vector<std::shared_ptr<DNSRecordContent>> d_custom;
95 std::shared_ptr<std::string> d_name; // the name of the policy
6da513b2 96 /* Yup, we are currently using the same TTL for every record for a given name */
8f618901 97 int32_t d_ttl;
e37e5795
OM
98 Priority d_priority;
99 PolicyKind d_kind;
100 PolicyType d_type;
6da513b2
RG
101
102 private:
103 DNSRecord getRecordFromCustom(const DNSName& qname, const std::shared_ptr<DNSRecordContent>& custom) const;
e37e5795 104 };
644dd1da 105
6b972d59
RG
106 class Zone {
107 public:
108 void clear()
109 {
110 d_qpolAddr.clear();
111 d_postpolAddr.clear();
112 d_propolName.clear();
598ac803 113 d_propolNSAddr.clear();
6b972d59
RG
114 d_qpolName.clear();
115 }
116 void reserve(size_t entriesCount)
117 {
118 d_qpolName.reserve(entriesCount);
119 }
120 void setName(const std::string& name)
121 {
122 d_name = std::make_shared<std::string>(name);
123 }
6791663c
RG
124 void setDomain(const DNSName& domain)
125 {
126 d_domain = domain;
127 }
128 void setSerial(uint32_t serial)
129 {
130 d_serial = serial;
131 }
132 void setRefresh(uint32_t refresh)
133 {
134 d_refresh = refresh;
135 }
6b972d59
RG
136 const std::shared_ptr<std::string> getName() const
137 {
138 return d_name;
139 }
4ba9d5dc
RG
140
141 DNSName getDomain() const
209955c7 142 {
143 return d_domain;
144 }
4ba9d5dc
RG
145
146 uint32_t getRefresh() const
209955c7 147 {
148 return d_refresh;
149 }
4ba9d5dc 150
6da513b2
RG
151 uint32_t getSerial() const
152 {
153 return d_serial;
154 }
155
4ba9d5dc
RG
156 size_t size() const
157 {
158 return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size();
4ba9d5dc
RG
159 }
160
6791663c 161 void dump(FILE * fp) const;
644dd1da 162
6da513b2 163 void addClientTrigger(const Netmask& nm, Policy&& pol);
d122dac0 164 void addQNameTrigger(const DNSName& nm, Policy&& pol, bool ignoreDuplicate=false);
6da513b2
RG
165 void addNSTrigger(const DNSName& dn, Policy&& pol);
166 void addNSIPTrigger(const Netmask& nm, Policy&& pol);
167 void addResponseTrigger(const Netmask& nm, Policy&& pol);
168
169 bool rmClientTrigger(const Netmask& nm, const Policy& pol);
170 bool rmQNameTrigger(const DNSName& nm, const Policy& pol);
171 bool rmNSTrigger(const DNSName& dn, const Policy& pol);
172 bool rmNSIPTrigger(const Netmask& nm, const Policy& pol);
173 bool rmResponseTrigger(const Netmask& nm, const Policy& pol);
6b972d59 174
272e9a00 175 bool findExactQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
272e9a00 176 bool findExactNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
6791663c
RG
177 bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
178 bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
179 bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
180
272e9a00
RG
181 bool hasClientPolicies() const
182 {
183 return !d_qpolAddr.empty();
184 }
185 bool hasQNamePolicies() const
186 {
187 return !d_qpolName.empty();
188 }
189 bool hasNSPolicies() const
190 {
191 return !d_propolName.empty();
192 }
193 bool hasNSIPPolicies() const
194 {
195 return !d_propolNSAddr.empty();
196 }
197 bool hasResponsePolicies() const
198 {
199 return !d_postpolAddr.empty();
200 }
e37e5795
OM
201 Priority getPriority() const {
202 return d_priority;
203 }
204 void setPriority(Priority p) {
205 d_priority = p;
63464fee
OM
206 for (auto& pair : d_qpolName) {
207 pair.second.d_priority = p;
79f64c2b 208 }
63464fee
OM
209 for (auto& pair : d_propolName) {
210 pair.second.d_priority = p;
79f64c2b 211 }
9bb0af03
OM
212 for (auto& pair : d_qpolAddr) {
213 pair.second.d_priority = p;
79f64c2b 214 }
9bb0af03
OM
215 for (auto& pair : d_propolNSAddr) {
216 pair.second.d_priority = p;
79f64c2b 217 }
9bb0af03
OM
218 for (auto& pair : d_postpolAddr) {
219 pair.second.d_priority = p;
79f64c2b 220 }
e37e5795 221 }
6791663c
RG
222 private:
223 static DNSName maskToRPZ(const Netmask& nm);
272e9a00
RG
224 static bool findExactNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol);
225 static bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol);
226 static void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol);
227 static void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol);
6791663c 228
6b972d59
RG
229 std::unordered_map<DNSName, Policy> d_qpolName; // QNAME trigger (RPZ)
230 NetmaskTree<Policy> d_qpolAddr; // Source address
231 std::unordered_map<DNSName, Policy> d_propolName; // NSDNAME (RPZ)
232 NetmaskTree<Policy> d_propolNSAddr; // NSIP (RPZ)
233 NetmaskTree<Policy> d_postpolAddr; // IP trigger (RPZ)
6791663c 234 DNSName d_domain;
6b972d59 235 std::shared_ptr<std::string> d_name;
6791663c
RG
236 uint32_t d_serial{0};
237 uint32_t d_refresh{0};
e37e5795 238 Priority d_priority;
6b972d59
RG
239 };
240
241 DNSFilterEngine();
242 void clear()
243 {
244 for(auto& z : d_zones) {
245 z->clear();
246 }
247 }
272e9a00
RG
248 void clearZones()
249 {
250 d_zones.clear();
251 }
6b972d59
RG
252 const std::shared_ptr<Zone> getZone(size_t zoneIdx) const
253 {
254 std::shared_ptr<Zone> result{nullptr};
255 if (zoneIdx < d_zones.size()) {
256 result = d_zones[zoneIdx];
257 }
258 return result;
259 }
6791663c
RG
260 const std::shared_ptr<Zone> getZone(const std::string& name) const
261 {
262 for (const auto zone : d_zones) {
263 const auto& zName = zone->getName();
264 if (zName && *zName == name) {
265 return zone;
266 }
267 }
268 return nullptr;
269 }
6b972d59
RG
270 size_t addZone(std::shared_ptr<Zone> newZone)
271 {
e37e5795 272 newZone->setPriority(d_zones.size());
6b972d59
RG
273 d_zones.push_back(newZone);
274 return (d_zones.size() - 1);
275 }
276 void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone)
277 {
278 if (newZone) {
279 assureZones(zoneIdx);
e37e5795 280 newZone->setPriority(zoneIdx);
6b972d59
RG
281 d_zones[zoneIdx] = newZone;
282 }
283 }
39ec5d29 284
2996400c
OM
285 bool getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& policy) const;
286 bool getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& policy) const;
287 bool getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& policy) const;
288 bool getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& policy) const;
289
290 // A few convenience methods for the unit test code
291 Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies, Priority p) const {
292 Policy policy;
293 policy.d_priority = p;
294 getQueryPolicy(qname, nm, discardedPolicies, policy);
295 return policy;
296 }
297
298 Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies, Priority p) const {
299 Policy policy;
300 policy.d_priority = p;
301 getProcessingPolicy(qname, discardedPolicies, policy);
302 return policy;
303 }
304
305 Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies, Priority p) const {
306 Policy policy;
307 policy.d_priority = p;
308 getProcessingPolicy(address, discardedPolicies, policy);
309 return policy;
310 }
311
312 Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies, Priority p) const {
313 Policy policy;
314 policy.d_priority = p;
315 getPostPolicy(records, discardedPolicies, policy);
316 return policy;
317 }
644dd1da 318
6b972d59 319 size_t size() const {
0e760497 320 return d_zones.size();
321 }
644dd1da 322private:
0a273054 323 void assureZones(size_t zone);
6b972d59 324 vector<std::shared_ptr<Zone>> d_zones;
644dd1da 325};