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