]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/filterpo.hh
Merge branch 'master' into rec-dump-rpz
[thirdparty/pdns.git] / pdns / filterpo.hh
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 */
22 #pragma once
23 #include "iputils.hh"
24 #include "dns.hh"
25 #include "dnsname.hh"
26 #include "dnsparser.hh"
27 #include <map>
28 #include <unordered_map>
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:
35
36 No action - just pass it on
37 Drop - drop a query, no response
38 NXDOMAIN - fake up an NXDOMAIN for the query
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:
44
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)
60 Finally, triggers are grouped in different zones. The "first" zone that has a match
61 is consulted. Then within that zone, rules again have precedences.
62 */
63
64
65 class DNSFilterEngine
66 {
67 public:
68 enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
69 enum class PolicyType { None, QName, ClientIP, ResponseIP, NSDName, NSIP };
70
71 struct Policy
72 {
73 Policy(): d_custom(nullptr), d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0)
74 {
75 }
76 bool operator==(const Policy& rhs) const
77 {
78 return d_kind == rhs.d_kind; // XXX check d_custom too!
79 }
80 std::string getKindToString() const;
81 DNSRecord getCustomRecord(const DNSName& qname) const;
82 DNSRecord getRecord(const DNSName& qname) const;
83
84 PolicyKind d_kind;
85 std::shared_ptr<DNSRecordContent> d_custom;
86 std::shared_ptr<std::string> d_name;
87 PolicyKind d_kind;
88 PolicyType d_type;
89 int32_t d_ttl;
90 };
91
92 class Zone {
93 public:
94 void clear()
95 {
96 d_qpolAddr.clear();
97 d_postpolAddr.clear();
98 d_propolName.clear();
99 d_propolNSAddr.clear();
100 d_qpolName.clear();
101 }
102 void reserve(size_t entriesCount)
103 {
104 d_qpolName.reserve(entriesCount);
105 }
106 void setName(const std::string& name)
107 {
108 d_name = std::make_shared<std::string>(name);
109 }
110 void setDomain(const DNSName& domain)
111 {
112 d_domain = domain;
113 }
114 void setSerial(uint32_t serial)
115 {
116 d_serial = serial;
117 }
118 void setRefresh(uint32_t refresh)
119 {
120 d_refresh = refresh;
121 }
122 const std::shared_ptr<std::string> getName() const
123 {
124 return d_name;
125 }
126 void dump(FILE * fp) const;
127
128 void addClientTrigger(const Netmask& nm, Policy pol);
129 void addQNameTrigger(const DNSName& nm, Policy pol);
130 void addNSTrigger(const DNSName& dn, Policy pol);
131 void addNSIPTrigger(const Netmask& nm, Policy pol);
132 void addResponseTrigger(const Netmask& nm, Policy pol);
133
134 bool rmClientTrigger(const Netmask& nm, Policy pol);
135 bool rmQNameTrigger(const DNSName& nm, Policy pol);
136 bool rmNSTrigger(const DNSName& dn, Policy pol);
137 bool rmNSIPTrigger(const Netmask& nm, Policy pol);
138 bool rmResponseTrigger(const Netmask& nm, Policy pol);
139
140 bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
141 bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
142 bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
143 bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
144 bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
145
146 private:
147 static DNSName maskToRPZ(const Netmask& nm);
148 bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const;
149 void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const;
150 void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const;
151
152 std::unordered_map<DNSName, Policy> d_qpolName; // QNAME trigger (RPZ)
153 NetmaskTree<Policy> d_qpolAddr; // Source address
154 std::unordered_map<DNSName, Policy> d_propolName; // NSDNAME (RPZ)
155 NetmaskTree<Policy> d_propolNSAddr; // NSIP (RPZ)
156 NetmaskTree<Policy> d_postpolAddr; // IP trigger (RPZ)
157 DNSName d_domain;
158 std::shared_ptr<std::string> d_name;
159 uint32_t d_serial{0};
160 uint32_t d_refresh{0};
161 };
162
163 DNSFilterEngine();
164 void clear()
165 {
166 for(auto& z : d_zones) {
167 z->clear();
168 }
169 }
170 const std::shared_ptr<Zone> getZone(size_t zoneIdx) const
171 {
172 std::shared_ptr<Zone> result{nullptr};
173 if (zoneIdx < d_zones.size()) {
174 result = d_zones[zoneIdx];
175 }
176 return result;
177 }
178 const std::shared_ptr<Zone> getZone(const std::string& name) const
179 {
180 for (const auto zone : d_zones) {
181 const auto& zName = zone->getName();
182 if (zName && *zName == name) {
183 return zone;
184 }
185 }
186 return nullptr;
187 }
188 size_t addZone(std::shared_ptr<Zone> newZone)
189 {
190 d_zones.push_back(newZone);
191 return (d_zones.size() - 1);
192 }
193 void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone)
194 {
195 if (newZone) {
196 assureZones(zoneIdx);
197 d_zones[zoneIdx] = newZone;
198 }
199 }
200
201 Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies) const;
202 Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies) const;
203 Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const;
204 Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const;
205
206 size_t size() const {
207 return d_zones.size();
208 }
209 private:
210 void assureZones(size_t zone);
211 vector<std::shared_ptr<Zone>> d_zones;
212 };