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 };
71 static std::string getKindToString(PolicyKind kind);
72 static std::string getTypeToString(PolicyType type);
76 Policy(): d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0)
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)
84 bool operator==(const Policy& rhs) const
86 return d_kind == rhs.d_kind && d_type == rhs.d_type && d_ttl == rhs.d_ttl && d_custom == rhs.d_custom;
88 std::vector<DNSRecord> getCustomRecords(const DNSName& qname, uint16_t qtype) const;
89 std::vector<DNSRecord> getRecords(const DNSName& qname) const;
91 std::vector<std::shared_ptr<DNSRecordContent>> d_custom;
92 std::shared_ptr<std::string> d_name; // the name of the policy
95 /* Yup, we are currently using the same TTL for every record for a given name */
99 DNSRecord getRecordFromCustom(const DNSName& qname, const std::shared_ptr<DNSRecordContent>& custom) const;
107 d_postpolAddr.clear();
108 d_propolName.clear();
109 d_propolNSAddr.clear();
112 void reserve(size_t entriesCount)
114 d_qpolName.reserve(entriesCount);
116 void setName(const std::string& name)
118 d_name = std::make_shared<std::string>(name);
120 void setDomain(const DNSName& domain)
124 void setSerial(uint32_t serial)
128 void setRefresh(uint32_t refresh)
132 const std::shared_ptr<std::string> getName() const
137 DNSName getDomain() const
142 uint32_t getRefresh() const
147 uint32_t getSerial() const
154 return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size();
158 void dump(FILE * fp) const;
160 void addClientTrigger(const Netmask& nm, Policy&& pol);
161 void addQNameTrigger(const DNSName& nm, Policy&& pol, bool ignoreDuplicate=false);
162 void addNSTrigger(const DNSName& dn, Policy&& pol);
163 void addNSIPTrigger(const Netmask& nm, Policy&& pol);
164 void addResponseTrigger(const Netmask& nm, Policy&& pol);
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);
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;
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;
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)
190 std::shared_ptr<std::string> d_name;
191 uint32_t d_serial{0};
192 uint32_t d_refresh{0};
198 for(auto& z : d_zones) {
202 const std::shared_ptr<Zone> getZone(size_t zoneIdx) const
204 std::shared_ptr<Zone> result{nullptr};
205 if (zoneIdx < d_zones.size()) {
206 result = d_zones[zoneIdx];
210 const std::shared_ptr<Zone> getZone(const std::string& name) const
212 for (const auto zone : d_zones) {
213 const auto& zName = zone->getName();
214 if (zName && *zName == name) {
220 size_t addZone(std::shared_ptr<Zone> newZone)
222 d_zones.push_back(newZone);
223 return (d_zones.size() - 1);
225 void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone)
228 assureZones(zoneIdx);
229 d_zones[zoneIdx] = newZone;
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;
238 size_t size() const {
239 return d_zones.size();
242 void assureZones(size_t zone);
243 vector<std::shared_ptr<Zone>> d_zones;