2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
26 #include "dnsparser.hh"
28 #include <unordered_map>
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.
34 We know the following actions:
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
41 Modified - "we fake an answer for you"
43 These actions can be caused by the following triggers:
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
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
56 Triggers meanwhile can apply to:
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.
68 enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
69 enum class PolicyType { None, QName, ClientIP, ResponseIP, NSDName, NSIP };
73 Policy(): d_custom(nullptr), d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0)
76 bool operator==(const Policy& rhs) const
78 return d_kind == rhs.d_kind; // XXX check d_custom too!
80 std::string getKindToString() const;
81 DNSRecord getCustomRecord(const DNSName& qname) const;
82 DNSRecord getRecord(const DNSName& qname) const;
84 std::shared_ptr<DNSRecordContent> d_custom;
85 std::shared_ptr<std::string> d_name;
96 d_postpolAddr.clear();
98 d_propolNSAddr.clear();
101 void reserve(size_t entriesCount)
103 d_qpolName.reserve(entriesCount);
105 void setName(const std::string& name)
107 d_name = std::make_shared<std::string>(name);
109 void setDomain(const DNSName& domain)
113 void setSerial(uint32_t serial)
117 void setRefresh(uint32_t refresh)
121 const std::shared_ptr<std::string> getName() const
126 DNSName getDomain() const
131 uint32_t getRefresh() const
138 return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size();
142 void dump(FILE * fp) const;
144 void addClientTrigger(const Netmask& nm, Policy pol);
145 void addQNameTrigger(const DNSName& nm, Policy pol);
146 void addNSTrigger(const DNSName& dn, Policy pol);
147 void addNSIPTrigger(const Netmask& nm, Policy pol);
148 void addResponseTrigger(const Netmask& nm, Policy pol);
150 bool rmClientTrigger(const Netmask& nm, Policy& pol);
151 bool rmQNameTrigger(const DNSName& nm, Policy& pol);
152 bool rmNSTrigger(const DNSName& dn, Policy& pol);
153 bool rmNSIPTrigger(const Netmask& nm, Policy& pol);
154 bool rmResponseTrigger(const Netmask& nm, Policy& pol);
156 bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
157 bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
158 bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
159 bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
160 bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
163 static DNSName maskToRPZ(const Netmask& nm);
164 bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const;
165 void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const;
166 void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const;
168 std::unordered_map<DNSName, Policy> d_qpolName; // QNAME trigger (RPZ)
169 NetmaskTree<Policy> d_qpolAddr; // Source address
170 std::unordered_map<DNSName, Policy> d_propolName; // NSDNAME (RPZ)
171 NetmaskTree<Policy> d_propolNSAddr; // NSIP (RPZ)
172 NetmaskTree<Policy> d_postpolAddr; // IP trigger (RPZ)
174 std::shared_ptr<std::string> d_name;
175 uint32_t d_serial{0};
176 uint32_t d_refresh{0};
182 for(auto& z : d_zones) {
186 const std::shared_ptr<Zone> getZone(size_t zoneIdx) const
188 std::shared_ptr<Zone> result{nullptr};
189 if (zoneIdx < d_zones.size()) {
190 result = d_zones[zoneIdx];
194 const std::shared_ptr<Zone> getZone(const std::string& name) const
196 for (const auto zone : d_zones) {
197 const auto& zName = zone->getName();
198 if (zName && *zName == name) {
204 size_t addZone(std::shared_ptr<Zone> newZone)
206 d_zones.push_back(newZone);
207 return (d_zones.size() - 1);
209 void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone)
212 assureZones(zoneIdx);
213 d_zones[zoneIdx] = newZone;
217 Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies) const;
218 Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies) const;
219 Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const;
220 Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const;
222 size_t size() const {
223 return d_zones.size();
226 void assureZones(size_t zone);
227 vector<std::shared_ptr<Zone>> d_zones;