]>
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 | */ | |
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 | ||
65 | class DNSFilterEngine | |
66 | { | |
67 | public: | |
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(); | |
155 | ||
156 | } | |
157 | ||
6791663c | 158 | void dump(FILE * fp) const; |
644dd1da | 159 | |
6da513b2 | 160 | void addClientTrigger(const Netmask& nm, Policy&& pol); |
d122dac0 | 161 | void addQNameTrigger(const DNSName& nm, Policy&& pol, bool ignoreDuplicate=false); |
6da513b2 RG |
162 | void addNSTrigger(const DNSName& dn, Policy&& pol); |
163 | void addNSIPTrigger(const Netmask& nm, Policy&& pol); | |
164 | void addResponseTrigger(const Netmask& nm, Policy&& pol); | |
165 | ||
166 | bool rmClientTrigger(const Netmask& nm, const Policy& pol); | |
167 | bool rmQNameTrigger(const DNSName& nm, const Policy& pol); | |
168 | bool rmNSTrigger(const DNSName& dn, const Policy& pol); | |
169 | bool rmNSIPTrigger(const Netmask& nm, const Policy& pol); | |
170 | bool rmResponseTrigger(const Netmask& nm, const Policy& pol); | |
6b972d59 | 171 | |
6791663c RG |
172 | bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const; |
173 | bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const; | |
174 | bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; | |
175 | bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; | |
176 | bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const; | |
177 | ||
178 | private: | |
179 | static DNSName maskToRPZ(const Netmask& nm); | |
180 | bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const; | |
181 | void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const; | |
182 | void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const; | |
183 | ||
6b972d59 RG |
184 | std::unordered_map<DNSName, Policy> d_qpolName; // QNAME trigger (RPZ) |
185 | NetmaskTree<Policy> d_qpolAddr; // Source address | |
186 | std::unordered_map<DNSName, Policy> d_propolName; // NSDNAME (RPZ) | |
187 | NetmaskTree<Policy> d_propolNSAddr; // NSIP (RPZ) | |
188 | NetmaskTree<Policy> d_postpolAddr; // IP trigger (RPZ) | |
6791663c | 189 | DNSName d_domain; |
6b972d59 | 190 | std::shared_ptr<std::string> d_name; |
6791663c RG |
191 | uint32_t d_serial{0}; |
192 | uint32_t d_refresh{0}; | |
6b972d59 RG |
193 | }; |
194 | ||
195 | DNSFilterEngine(); | |
196 | void clear() | |
197 | { | |
198 | for(auto& z : d_zones) { | |
199 | z->clear(); | |
200 | } | |
201 | } | |
202 | const std::shared_ptr<Zone> getZone(size_t zoneIdx) const | |
203 | { | |
204 | std::shared_ptr<Zone> result{nullptr}; | |
205 | if (zoneIdx < d_zones.size()) { | |
206 | result = d_zones[zoneIdx]; | |
207 | } | |
208 | return result; | |
209 | } | |
6791663c RG |
210 | const std::shared_ptr<Zone> getZone(const std::string& name) const |
211 | { | |
212 | for (const auto zone : d_zones) { | |
213 | const auto& zName = zone->getName(); | |
214 | if (zName && *zName == name) { | |
215 | return zone; | |
216 | } | |
217 | } | |
218 | return nullptr; | |
219 | } | |
6b972d59 RG |
220 | size_t addZone(std::shared_ptr<Zone> newZone) |
221 | { | |
222 | d_zones.push_back(newZone); | |
223 | return (d_zones.size() - 1); | |
224 | } | |
225 | void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone) | |
226 | { | |
227 | if (newZone) { | |
228 | assureZones(zoneIdx); | |
229 | d_zones[zoneIdx] = newZone; | |
230 | } | |
231 | } | |
39ec5d29 | 232 | |
0a273054 RG |
233 | Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies) const; |
234 | Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies) const; | |
235 | Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const; | |
236 | Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const; | |
644dd1da | 237 | |
6b972d59 | 238 | size_t size() const { |
0e760497 | 239 | return d_zones.size(); |
240 | } | |
644dd1da | 241 | private: |
0a273054 | 242 | void assureZones(size_t zone); |
6b972d59 | 243 | vector<std::shared_ptr<Zone>> d_zones; |
644dd1da | 244 | }; |