d_zones.resize(zone+1);
}
-void DNSFilterEngine::Zone::addClientTrigger(const Netmask& nm, Policy pol)
+void DNSFilterEngine::Zone::addClientTrigger(const Netmask& nm, Policy&& pol)
{
pol.d_name = d_name;
pol.d_type = PolicyType::ClientIP;
- d_qpolAddr.insert(nm).second=pol;
+ d_qpolAddr.insert(nm).second=std::move(pol);
}
-void DNSFilterEngine::Zone::addResponseTrigger(const Netmask& nm, Policy pol)
+void DNSFilterEngine::Zone::addResponseTrigger(const Netmask& nm, Policy&& pol)
{
pol.d_name = d_name;
pol.d_type = PolicyType::ResponseIP;
- d_postpolAddr.insert(nm).second=pol;
+ d_postpolAddr.insert(nm).second=std::move(pol);
}
-void DNSFilterEngine::Zone::addQNameTrigger(const DNSName& n, Policy pol)
+void DNSFilterEngine::Zone::addQNameTrigger(const DNSName& n, Policy&& pol)
{
- pol.d_name = d_name;
- pol.d_type = PolicyType::QName;
- d_qpolName[n]=pol;
+ auto it = d_qpolName.find(n);
+
+ if (it != d_qpolName.end()) {
+ auto& existingPol = it->second;
+
+ if (existingPol.d_kind != pol.d_kind) {
+ throw std::runtime_error("Adding a QName-based filter policy of kind " + getKindToString(existingPol.d_kind) + " but a policy of kind " + getKindToString(existingPol.d_kind) + " already exists for the following QName: " + n.toString());
+ }
+
+ if (existingPol.d_kind != PolicyKind::Custom) {
+ throw std::runtime_error("Adding a QName-based filter policy of kind " + getKindToString(existingPol.d_kind) + " but there was already an existing policy for the following QName: " + n.toString());
+ }
+
+ existingPol.d_custom.reserve(existingPol.d_custom.size() + pol.d_custom.size());
+
+ for (auto& custom : pol.d_custom) {
+ existingPol.d_custom.emplace_back(std::move(custom));
+ }
+ }
+ else {
+ auto& qpol = d_qpolName.insert({n, std::move(pol)}).first->second;
+ qpol.d_name = d_name;
+ qpol.d_type = PolicyType::QName;
+ }
}
-void DNSFilterEngine::Zone::addNSTrigger(const DNSName& n, Policy pol)
+void DNSFilterEngine::Zone::addNSTrigger(const DNSName& n, Policy&& pol)
{
pol.d_name = d_name;
pol.d_type = PolicyType::NSDName;
- d_propolName[n]=pol;
+ d_propolName.insert({n, std::move(pol)});
}
-void DNSFilterEngine::Zone::addNSIPTrigger(const Netmask& nm, Policy pol)
+void DNSFilterEngine::Zone::addNSIPTrigger(const Netmask& nm, Policy&& pol)
{
pol.d_name = d_name;
pol.d_type = PolicyType::NSIP;
- d_propolNSAddr.insert(nm).second = pol;
+ d_propolNSAddr.insert(nm).second = std::move(pol);
}
-bool DNSFilterEngine::Zone::rmClientTrigger(const Netmask& nm, Policy& pol)
+bool DNSFilterEngine::Zone::rmClientTrigger(const Netmask& nm, const Policy& pol)
{
d_qpolAddr.erase(nm);
return true;
}
-bool DNSFilterEngine::Zone::rmResponseTrigger(const Netmask& nm, Policy& pol)
+bool DNSFilterEngine::Zone::rmResponseTrigger(const Netmask& nm, const Policy& pol)
{
d_postpolAddr.erase(nm);
return true;
}
-bool DNSFilterEngine::Zone::rmQNameTrigger(const DNSName& n, Policy& pol)
+bool DNSFilterEngine::Zone::rmQNameTrigger(const DNSName& n, const Policy& pol)
{
- d_qpolName.erase(n); // XXX verify we had identical policy?
- return true;
+ auto it = d_qpolName.find(n);
+ if (it == d_qpolName.end()) {
+ return false;
+ }
+
+ auto& existing = it->second;
+ if (existing.d_kind != DNSFilterEngine::PolicyKind::Custom) {
+ d_qpolName.erase(it);
+ return true;
+ }
+
+ /* for custom types, we might have more than one type,
+ and then we need to remove only the right ones. */
+ if (existing.d_custom.size() <= 1) {
+ d_qpolName.erase(it);
+ return true;
+ }
+
+ bool result = false;
+ for (auto& toremove : pol.d_custom) {
+ for (auto it = existing.d_custom.begin(); it != existing.d_custom.end(); ++it) {
+ if (**it == *toremove) {
+ existing.d_custom.erase(it);
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
}
-bool DNSFilterEngine::Zone::rmNSTrigger(const DNSName& n, Policy& pol)
+bool DNSFilterEngine::Zone::rmNSTrigger(const DNSName& n, const Policy& pol)
{
d_propolName.erase(n); // XXX verify policy matched? =pol;
return true;
}
-bool DNSFilterEngine::Zone::rmNSIPTrigger(const Netmask& nm, Policy& pol)
+bool DNSFilterEngine::Zone::rmNSIPTrigger(const Netmask& nm, const Policy& pol)
{
d_propolNSAddr.erase(nm);
return true;
}
-DNSRecord DNSFilterEngine::Policy::getCustomRecord(const DNSName& qname) const
+DNSRecord DNSFilterEngine::Policy::getRecordFromCustom(const DNSName& qname, const std::shared_ptr<DNSRecordContent>& custom) const
+{
+ DNSRecord dr;
+ dr.d_name = qname;
+ dr.d_type = custom->getType();
+ dr.d_ttl = d_ttl;
+ dr.d_class = QClass::IN;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_content = custom;
+
+ if (dr.d_type == QType::CNAME) {
+ const auto content = std::dynamic_pointer_cast<CNAMERecordContent>(custom);
+ if (content) {
+ DNSName target = content->getTarget();
+ if (target.isWildcard()) {
+ target.chopOff();
+ dr.d_content = std::make_shared<CNAMERecordContent>(qname + target);
+ }
+ }
+ }
+
+ return dr;
+}
+
+std::vector<DNSRecord> DNSFilterEngine::Policy::getCustomRecords(const DNSName& qname, uint16_t qtype) const
{
if (d_kind != PolicyKind::Custom) {
throw std::runtime_error("Asking for a custom record from a filtering policy of a non-custom type");
}
- DNSRecord result;
- result.d_name = qname;
- result.d_type = d_custom->getType();
- result.d_ttl = d_ttl;
- result.d_class = QClass::IN;
- result.d_place = DNSResourceRecord::ANSWER;
- result.d_content = d_custom;
+ std::vector<DNSRecord> result;
- if (result.d_type == QType::CNAME) {
- const auto content = std::dynamic_pointer_cast<CNAMERecordContent>(d_custom);
- if (content) {
- DNSName target = content->getTarget();
- if (target.isWildcard()) {
- target.chopOff();
- result.d_content = std::make_shared<CNAMERecordContent>(qname + target);
+ for (const auto& custom : d_custom) {
+ if (qtype != QType::ANY && qtype != custom->getType() && custom->getType() != QType::CNAME) {
+ continue;
+ }
+
+ DNSRecord dr;
+ dr.d_name = qname;
+ dr.d_type = custom->getType();
+ dr.d_ttl = d_ttl;
+ dr.d_class = QClass::IN;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_content = custom;
+
+ if (dr.d_type == QType::CNAME) {
+ const auto content = std::dynamic_pointer_cast<CNAMERecordContent>(custom);
+ if (content) {
+ DNSName target = content->getTarget();
+ if (target.isWildcard()) {
+ target.chopOff();
+ dr.d_content = std::make_shared<CNAMERecordContent>(qname + target);
+ }
}
}
+
+ result.emplace_back(getRecordFromCustom(qname, custom));
}
return result;
}
-std::string DNSFilterEngine::Policy::getKindToString() const
+std::string DNSFilterEngine::getKindToString(DNSFilterEngine::PolicyKind kind)
{
static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru.");
static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"),
rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip.");
static const std::string rpzPrefix("rpz-");
- switch(d_kind) {
+ switch(kind) {
case DNSFilterEngine::PolicyKind::NoAction:
return noaction.toString();
case DNSFilterEngine::PolicyKind::Drop:
}
}
-DNSRecord DNSFilterEngine::Policy::getRecord(const DNSName& qname) const
+std::string DNSFilterEngine::getTypeToString(DNSFilterEngine::PolicyType type)
{
- DNSRecord dr;
+ switch(type) {
+ case DNSFilterEngine::PolicyType::None:
+ return "none";
+ case DNSFilterEngine::PolicyType::QName:
+ return "QName";
+ case DNSFilterEngine::PolicyType::ClientIP:
+ return "Client IP";
+ case DNSFilterEngine::PolicyType::ResponseIP:
+ return "Response IP";
+ case DNSFilterEngine::PolicyType::NSDName:
+ return "Name Server Name";
+ case DNSFilterEngine::PolicyType::NSIP:
+ return "Name Server IP";
+ default:
+ throw std::runtime_error("Unexpected DNSFilterEngine::Policy type");
+ }
+}
+
+std::vector<DNSRecord> DNSFilterEngine::Policy::getRecords(const DNSName& qname) const
+{
+ std::vector<DNSRecord> result;
if (d_kind == PolicyKind::Custom) {
- dr = getCustomRecord(qname);
+ result = getCustomRecords(qname, QType::ANY);
}
else {
+ DNSRecord dr;
dr.d_name = qname;
dr.d_ttl = static_cast<uint32_t>(d_ttl);
dr.d_type = QType::CNAME;
dr.d_class = QClass::IN;
- dr.d_content = DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString());
+ dr.d_content = DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString(d_kind));
+ result.push_back(std::move(dr));
}
- return dr;
+ return result;
}
void DNSFilterEngine::Zone::dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const
{
- DNSRecord dr = pol.getRecord(name);
- fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+ auto records = pol.getRecords(name);
+ for (const auto& dr : records) {
+ fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+ }
}
DNSName DNSFilterEngine::Zone::maskToRPZ(const Netmask& nm)
DNSName full = maskToRPZ(nm);
full += name;
- DNSRecord dr = pol.getRecord(full);
- fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+ auto records = pol.getRecords(full);
+ for (const auto& dr : records) {
+ fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+ }
}
void DNSFilterEngine::Zone::dump(FILE* fp) const
enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
enum class PolicyType { None, QName, ClientIP, ResponseIP, NSDName, NSIP };
+ static std::string getKindToString(PolicyKind kind);
+ static std::string getTypeToString(PolicyType type);
+
struct Policy
{
- Policy(): d_custom(nullptr), d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0)
+ Policy(): d_name(nullptr), d_kind(PolicyKind::NoAction), d_type(PolicyType::None), d_ttl(0)
+ {
+ }
+
+ 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)
{
}
+
bool operator==(const Policy& rhs) const
{
- return d_kind == rhs.d_kind; // XXX check d_custom too!
+ return d_kind == rhs.d_kind && d_type == rhs.d_type && d_ttl == rhs.d_ttl && d_custom == rhs.d_custom;
}
- std::string getKindToString() const;
- DNSRecord getCustomRecord(const DNSName& qname) const;
- DNSRecord getRecord(const DNSName& qname) const;
+ std::vector<DNSRecord> getCustomRecords(const DNSName& qname, uint16_t qtype) const;
+ std::vector<DNSRecord> getRecords(const DNSName& qname) const;
- std::shared_ptr<DNSRecordContent> d_custom;
- std::shared_ptr<std::string> d_name;
+ std::vector<std::shared_ptr<DNSRecordContent>> d_custom;
+ std::shared_ptr<std::string> d_name; // the name of the policy
PolicyKind d_kind;
PolicyType d_type;
+ /* Yup, we are currently using the same TTL for every record for a given name */
int32_t d_ttl;
- };
+
+ private:
+ DNSRecord getRecordFromCustom(const DNSName& qname, const std::shared_ptr<DNSRecordContent>& custom) const;
+};
class Zone {
public:
return d_refresh;
}
+ uint32_t getSerial() const
+ {
+ return d_serial;
+ }
+
size_t size() const
{
return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size();
void dump(FILE * fp) const;
- void addClientTrigger(const Netmask& nm, Policy pol);
- void addQNameTrigger(const DNSName& nm, Policy pol);
- void addNSTrigger(const DNSName& dn, Policy pol);
- void addNSIPTrigger(const Netmask& nm, Policy pol);
- void addResponseTrigger(const Netmask& nm, Policy pol);
-
- bool rmClientTrigger(const Netmask& nm, Policy& pol);
- bool rmQNameTrigger(const DNSName& nm, Policy& pol);
- bool rmNSTrigger(const DNSName& dn, Policy& pol);
- bool rmNSIPTrigger(const Netmask& nm, Policy& pol);
- bool rmResponseTrigger(const Netmask& nm, Policy& pol);
+ void addClientTrigger(const Netmask& nm, Policy&& pol);
+ void addQNameTrigger(const DNSName& nm, Policy&& pol);
+ void addNSTrigger(const DNSName& dn, Policy&& pol);
+ void addNSIPTrigger(const Netmask& nm, Policy&& pol);
+ void addResponseTrigger(const Netmask& nm, Policy&& pol);
+
+ bool rmClientTrigger(const Netmask& nm, const Policy& pol);
+ bool rmQNameTrigger(const DNSName& nm, const Policy& pol);
+ bool rmNSTrigger(const DNSName& dn, const Policy& pol);
+ bool rmNSIPTrigger(const Netmask& nm, const Policy& pol);
+ bool rmResponseTrigger(const Netmask& nm, const Policy& pol);
bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
d_lw->registerMember<DNSFilterEngine::Policy, std::string>("policyCustom",
[](const DNSFilterEngine::Policy& pol) -> std::string {
- if(pol.d_custom)
- return pol.d_custom->getZoneRepresentation();
- return std::string();
+ std::string result;
+ if (pol.d_kind != DNSFilterEngine::PolicyKind::Custom) {
+ return result;
+ }
+
+ for (const auto& dr : pol.d_custom) {
+ if (!result.empty()) {
+ result += "\n";
+ }
+ result += dr->getZoneRepresentation();
+ }
+
+ return result;
},
[](DNSFilterEngine::Policy& pol, const std::string& content) {
// Only CNAMES for now, when we ever add a d_custom_type, there will be pain
- pol.d_custom = DNSRecordContent::mastermake(QType::CNAME, 1, content);
+ pol.d_custom.clear();
+ pol.d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN, content));
}
);
d_lw->registerFunction("getDH", &DNSQuestion::getDH);
bool oldWantsRPZ = sr.getWantsRPZ();
sr.setWantsRPZ(false);
vector<DNSRecord> ans;
- res = sr.beginResolve(DNSName(spoofed.d_content->getZoneRepresentation()), qtype, 1, ans);
+ res = sr.beginResolve(DNSName(spoofed.d_content->getZoneRepresentation()), qtype, QClass::IN, ans);
for (const auto& rec : ans) {
if(rec.d_place == DNSResourceRecord::ANSWER) {
ret.push_back(rec);
/* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
int res = RCode::NoError;
DNSFilterEngine::Policy appliedPolicy;
- DNSRecord spoofed;
+ std::vector<DNSRecord> spoofed;
RecursorLua4::DNSQuestion dq(dc->d_source, dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ, logResponse);
dq.ednsFlags = &edo.d_extFlags;
dq.ednsOptions = &ednsOpts;
case DNSFilterEngine::PolicyKind::Custom:
g_stats.policyResults[appliedPolicy.d_kind]++;
res=RCode::NoError;
- spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
- ret.push_back(spoofed);
- handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
+ for (const auto& dr : spoofed) {
+ ret.push_back(dr);
+ handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ }
goto haveAnswer;
case DNSFilterEngine::PolicyKind::Truncate:
if(!dc->d_tcp) {
case DNSFilterEngine::PolicyKind::Custom:
ret.clear();
res=RCode::NoError;
- spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
- ret.push_back(spoofed);
- handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
+ for (const auto& dr : spoofed) {
+ ret.push_back(dr);
+ handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ }
goto haveAnswer;
}
}
case DNSFilterEngine::PolicyKind::Custom:
ret.clear();
res=RCode::NoError;
- spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname);
- ret.push_back(spoofed);
- handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ spoofed=appliedPolicy.getCustomRecords(dc->d_mdp.d_qname, dc->d_mdp.d_qtype);
+ for (const auto& dr : spoofed) {
+ ret.push_back(dr);
+ handleRPZCustom(dr, QType(dc->d_mdp.d_qtype), sr, res, ret);
+ }
goto haveAnswer;
}
}
defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<uint32_t>(constGet(have, "defpol"));
defpol->d_name = std::make_shared<std::string>(polName);
if(defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
- defpol->d_custom=
- DNSRecordContent::mastermake(QType::CNAME, 1,
- boost::get<string>(constGet(have,"defcontent"))
- );
+ defpol->d_custom.push_back(DNSRecordContent::mastermake(QType::CNAME, QClass::IN,
+ boost::get<string>(constGet(have,"defcontent"))));
if(have.count("defttl"))
defpol->d_ttl = static_cast<int32_t>(boost::get<uint32_t>(constGet(have, "defttl")));
test-dnsparser_hh.cc \
test-dnsrecords_cc.cc \
test-ednsoptions_cc.cc \
+ test-filterpo_cc.cc \
test-iputils_hh.cc \
test-ixfr_cc.cc \
test-misc_hh.cc \
--- /dev/null
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+
+#include "dnsrecords.hh"
+#include "filterpo.hh"
+
+BOOST_AUTO_TEST_CASE(test_filter_policies_basic) {
+ DNSFilterEngine dfe;
+
+ std::string zoneName("Unit test policy 0");
+ auto zone = std::make_shared<DNSFilterEngine::Zone>();
+ zone->setName(zoneName);
+ BOOST_CHECK_EQUAL(*(zone->getName()), zoneName);
+ zone->setDomain(DNSName("powerdns.com."));
+ BOOST_CHECK_EQUAL(zone->getDomain(), DNSName("powerdns.com."));
+ zone->setSerial(42);
+ BOOST_CHECK_EQUAL(zone->getSerial(), 42);
+ zone->setRefresh(99);
+ BOOST_CHECK_EQUAL(zone->getRefresh(), 99);
+
+ const ComboAddress nsIP("192.0.2.1");
+ const DNSName nsName("ns.bad.wolf.");
+ const ComboAddress clientIP("192.0.2.128");
+ const DNSName blockedName("blocked.");
+ const ComboAddress responseIP("192.0.2.254");
+ BOOST_CHECK_EQUAL(zone->size(), 0);
+ zone->addClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::ClientIP));
+ BOOST_CHECK_EQUAL(zone->size(), 1);
+ zone->addQNameTrigger(blockedName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::QName));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+ zone->addNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::NSIP));
+ BOOST_CHECK_EQUAL(zone->size(), 3);
+ zone->addNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::NSDName));
+ BOOST_CHECK_EQUAL(zone->size(), 4);
+ zone->addResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::ResponseIP));
+ BOOST_CHECK_EQUAL(zone->size(), 5);
+
+ size_t zoneIdx = dfe.addZone(zone);
+
+ BOOST_CHECK_EQUAL(dfe.size(), 1);
+ BOOST_CHECK(dfe.getZone(zoneName) == zone);
+ BOOST_CHECK(dfe.getZone(zoneIdx) == zone);
+
+ dfe.setZone(zoneIdx, zone);
+
+ BOOST_CHECK_EQUAL(dfe.size(), 1);
+ BOOST_CHECK(dfe.getZone(zoneName) == zone);
+ BOOST_CHECK(dfe.getZone(zoneIdx) == zone);
+
+ {
+ /* blocked NS name */
+ const auto matchingPolicy = dfe.getProcessingPolicy(nsName, std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::NSDName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findNSPolicy(nsName, zonePolicy));
+ BOOST_CHECK(zonePolicy == matchingPolicy);
+ }
+
+ {
+ /* allowed NS name */
+ const auto matchingPolicy = dfe.getProcessingPolicy(DNSName("ns.bad.rabbit."), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findNSPolicy(DNSName("ns.bad.rabbit."), zonePolicy) == false);
+ }
+
+ {
+ /* blocked NS IP */
+ const auto matchingPolicy = dfe.getProcessingPolicy(nsIP, std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::NSIP);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findNSIPPolicy(nsIP, zonePolicy));
+ BOOST_CHECK(zonePolicy == matchingPolicy);
+ }
+
+ {
+ /* allowed NS IP */
+ const auto matchingPolicy = dfe.getProcessingPolicy(ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findNSIPPolicy(ComboAddress("192.0.2.142"), zonePolicy) == false);
+ }
+
+ {
+ /* blocked qname */
+ const auto matchingPolicy = dfe.getQueryPolicy(blockedName, ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findQNamePolicy(blockedName, zonePolicy));
+ BOOST_CHECK(zonePolicy == matchingPolicy);
+ }
+
+ {
+ /* blocked client IP */
+ const auto matchingPolicy = dfe.getQueryPolicy(DNSName("totally.legit."), clientIP, std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::ClientIP);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findClientPolicy(clientIP, zonePolicy));
+ BOOST_CHECK(zonePolicy == matchingPolicy);
+ }
+
+ {
+ /* not blocked */
+ const auto matchingPolicy = dfe.getQueryPolicy(DNSName("totally.legit."), ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findClientPolicy(ComboAddress("192.0.2.142"), zonePolicy) == false);
+ BOOST_CHECK(zone->findQNamePolicy(DNSName("totally.legit."), zonePolicy) == false);
+ }
+
+ {
+ /* blocked A */
+ DNSRecord dr;
+ dr.d_type = QType::A;
+ dr.d_content = DNSRecordContent::mastermake(QType::A, QClass::IN, responseIP.toString());
+ const auto matchingPolicy = dfe.getPostPolicy({ dr }, std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::ResponseIP);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Drop);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findResponsePolicy(responseIP, zonePolicy));
+ BOOST_CHECK(zonePolicy == matchingPolicy);
+ }
+
+ {
+ /* allowed A */
+ DNSRecord dr;
+ dr.d_type = QType::A;
+ dr.d_content = DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.142");
+ const auto matchingPolicy = dfe.getPostPolicy({ dr }, std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
+ DNSFilterEngine::Policy zonePolicy;
+ BOOST_CHECK(zone->findResponsePolicy(ComboAddress("192.0.2.142"), zonePolicy) == false);
+ }
+
+ BOOST_CHECK_EQUAL(zone->size(), 5);
+ zone->rmClientTrigger(Netmask(clientIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::ClientIP));
+ BOOST_CHECK_EQUAL(zone->size(), 4);
+ zone->rmQNameTrigger(blockedName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::QName));
+ BOOST_CHECK_EQUAL(zone->size(), 3);
+ zone->rmNSIPTrigger(Netmask(nsIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::NSIP));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+ zone->rmNSTrigger(nsName, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::NSDName));
+ BOOST_CHECK_EQUAL(zone->size(), 1);
+ zone->rmResponseTrigger(Netmask(responseIP, 32), DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Drop, DNSFilterEngine::PolicyType::ResponseIP));
+ BOOST_CHECK_EQUAL(zone->size(), 0);
+
+ /* DNSFilterEngine::clear() calls clear() on all zones, but keeps the zones */
+ dfe.clear();
+ BOOST_CHECK_EQUAL(dfe.size(), 1);
+ BOOST_CHECK(dfe.getZone(zoneName) == zone);
+ BOOST_CHECK(dfe.getZone(zoneIdx) == zone);
+}
+
+BOOST_AUTO_TEST_CASE(test_filter_policies_local_data) {
+ DNSFilterEngine dfe;
+
+ std::string zoneName("Unit test policy local data");
+ auto zone = std::make_shared<DNSFilterEngine::Zone>();
+ zone->setName(zoneName);
+
+ const DNSName bad1("bad1.example.com.");
+ const DNSName bad2("bad2.example.com.");
+
+ zone->addQNameTrigger(bad1, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden.example.net.") } ));
+ BOOST_CHECK_EQUAL(zone->size(), 1);
+
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1") } ));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.2") } ));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+
+ zone->addQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::MX, QClass::IN, "10 garden-mail.example.net.") } ));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+
+ dfe.addZone(zone);
+
+ {
+ /* exact type does not exist, but we have a CNAME */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad1, ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+ auto records = matchingPolicy.getCustomRecords(bad1, QType::A);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::CNAME);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<CNAMERecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getTarget().toString(), "garden.example.net.");
+ }
+
+ {
+ /* exact type exists */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad2, ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+
+ {
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::A);
+ BOOST_REQUIRE_EQUAL(records.size(), 2);
+ {
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<ARecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getCA().toString(), "192.0.2.1");
+ }
+ {
+ const auto& record = records.at(1);
+ BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<ARecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getCA().toString(), "192.0.2.2");
+ }
+ }
+
+ {
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::MX);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::MX);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<MXRecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->d_mxname.toString(), "garden-mail.example.net.");
+ }
+
+ {
+ /* the name exists but there is no CNAME nor matching type, so NODATA */
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::AAAA);
+ BOOST_CHECK_EQUAL(records.size(), 0);
+ }
+ }
+
+ /* remove only one entry, one of the A local records */
+ zone->rmQNameTrigger(bad2, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::A, QClass::IN, "192.0.2.1") } ));
+ BOOST_CHECK_EQUAL(zone->size(), 2);
+
+ {
+ /* exact type exists */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad2, ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+
+ {
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::A);
+ BOOST_REQUIRE_EQUAL(records.size(), 1);
+ {
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::A);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<ARecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getCA().toString(), "192.0.2.2");
+ }
+ }
+
+ {
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::MX);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::MX);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<MXRecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->d_mxname.toString(), "garden-mail.example.net.");
+ }
+
+ {
+ /* the name exists but there is no CNAME nor matching type, so NODATA */
+ auto records = matchingPolicy.getCustomRecords(bad2, QType::AAAA);
+ BOOST_CHECK_EQUAL(records.size(), 0);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_multiple_filter_policies) {
+ DNSFilterEngine dfe;
+
+ auto zone1 = std::make_shared<DNSFilterEngine::Zone>();
+ zone1->setName("Unit test policy 0");
+
+ auto zone2 = std::make_shared<DNSFilterEngine::Zone>();
+ zone2->setName("Unit test policy 1");
+
+ const DNSName bad("bad.example.com.");
+
+ zone1->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden1.example.net.") } ));
+ zone2->addQNameTrigger(bad, DNSFilterEngine::Policy(DNSFilterEngine::PolicyKind::Custom, DNSFilterEngine::PolicyType::QName, 0, nullptr, { DNSRecordContent::mastermake(QType::CNAME, QClass::IN, "garden2.example.net.") } ));
+
+ dfe.addZone(zone1);
+ dfe.addZone(zone2);
+
+ {
+ /* zone 1 should match first */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad, ComboAddress("192.0.2.142"), std::unordered_map<std::string,bool>());
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+ auto records = matchingPolicy.getCustomRecords(bad, QType::A);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::CNAME);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<CNAMERecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getTarget().toString(), "garden1.example.net.");
+ }
+
+ {
+ /* zone 1 should still match if zone 2 has been disabled */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad, ComboAddress("192.0.2.142"), { { *(zone2->getName()), true } });
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+ auto records = matchingPolicy.getCustomRecords(bad, QType::A);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::CNAME);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<CNAMERecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getTarget().toString(), "garden1.example.net.");
+ }
+
+ {
+ /* if zone 1 is disabled, zone 2 should match */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad, ComboAddress("192.0.2.142"), { { *(zone1->getName()), true } });
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::QName);
+ BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom);
+ auto records = matchingPolicy.getCustomRecords(bad, QType::A);
+ BOOST_CHECK_EQUAL(records.size(), 1);
+ const auto& record = records.at(0);
+ BOOST_CHECK(record.d_type == QType::CNAME);
+ BOOST_CHECK(record.d_class == QClass::IN);
+ auto content = std::dynamic_pointer_cast<CNAMERecordContent>(record.d_content);
+ BOOST_CHECK(content != nullptr);
+ BOOST_CHECK_EQUAL(content->getTarget().toString(), "garden2.example.net.");
+ }
+
+ {
+ /* if both zones are disabled, we should not match */
+ const auto matchingPolicy = dfe.getQueryPolicy(bad, ComboAddress("192.0.2.142"), { { *(zone1->getName()), true }, { *(zone2->getName()), true } });
+ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None);
+ }
+
+}
pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
zone->setName("Unit test policy 0");
- zone->addNSIPTrigger(Netmask(ns, 32), pol);
+ zone->addNSIPTrigger(Netmask(ns, 32), std::move(pol));
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.addZone(zone);
g_luaconfs.setState(luaconfsCopy);
pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
zone->setName("Unit test policy 0");
- zone->addNSIPTrigger(Netmask(ns, 128), pol);
+ zone->addNSIPTrigger(Netmask(ns, 128), std::move(pol));
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.addZone(zone);
g_luaconfs.setState(luaconfsCopy);
pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
zone->setName("Unit test policy 0");
- zone->addNSTrigger(nsName, pol);
+ zone->addNSTrigger(nsName, std::move(pol));
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.addZone(zone);
g_luaconfs.setState(luaconfsCopy);
pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
zone->setName("Unit test policy 0");
- zone->addNSIPTrigger(Netmask(ns, 128), pol);
- zone->addNSTrigger(nsName, pol);
+ zone->addNSIPTrigger(Netmask(ns, 128), DNSFilterEngine::Policy(pol));
+ zone->addNSTrigger(nsName, std::move(pol));
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.addZone(zone);
g_luaconfs.setState(luaconfsCopy);
}
else {
pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
- pol.d_custom = dr.d_content;
+ pol.d_custom.emplace_back(dr.d_content);
// cerr<<"Wants custom "<<crcTarget<<" for "<<dr.d_name<<": ";
}
}
}
else {
pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
- pol.d_custom = dr.d_content;
+ pol.d_custom.emplace_back(dr.d_content);
// cerr<<"Wants custom "<<dr.d_content->getZoneRepresentation()<<" for "<<dr.d_name<<": ";
}
}
if(dr.d_name.isPartOf(rpzNSDname)) {
DNSName filt=dr.d_name.makeRelative(rpzNSDname);
if(addOrRemove)
- zone->addNSTrigger(filt, pol);
+ zone->addNSTrigger(filt, std::move(pol));
else
- zone->rmNSTrigger(filt, pol);
+ zone->rmNSTrigger(filt, std::move(pol));
} else if(dr.d_name.isPartOf(rpzClientIP)) {
DNSName filt=dr.d_name.makeRelative(rpzClientIP);
auto nm=makeNetmaskFromRPZ(filt);
if(addOrRemove)
- zone->addClientTrigger(nm, pol);
+ zone->addClientTrigger(nm, std::move(pol));
else
- zone->rmClientTrigger(nm, pol);
+ zone->rmClientTrigger(nm, std::move(pol));
} else if(dr.d_name.isPartOf(rpzIP)) {
// cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
DNSName filt=dr.d_name.makeRelative(rpzIP);
auto nm=makeNetmaskFromRPZ(filt);
if(addOrRemove)
- zone->addResponseTrigger(nm, pol);
+ zone->addResponseTrigger(nm, std::move(pol));
else
- zone->rmResponseTrigger(nm, pol);
+ zone->rmResponseTrigger(nm, std::move(pol));
} else if(dr.d_name.isPartOf(rpzNSIP)) {
DNSName filt=dr.d_name.makeRelative(rpzNSIP);
auto nm=makeNetmaskFromRPZ(filt);
if(addOrRemove)
- zone->addNSIPTrigger(nm, pol);
+ zone->addNSIPTrigger(nm, std::move(pol));
else
- zone->rmNSIPTrigger(nm, pol);
+ zone->rmNSIPTrigger(nm, std::move(pol));
} else {
if(addOrRemove)
- zone->addQNameTrigger(dr.d_name, pol);
+ zone->addQNameTrigger(dr.d_name, std::move(pol));
else
- zone->rmQNameTrigger(dr.d_name, pol);
+ zone->rmQNameTrigger(dr.d_name, std::move(pol));
}
}
dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
dns.rrset.from_text('d.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
- dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
+ dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1', '192.0.2.2'),
+ dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.MX, '10 mx.example.'),
+ dns.rrset.from_text('f.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'e.example.'),
+ dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
+ ]
+ elif newSerial == 7:
+ records = [
+ dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
+ dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
+ dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1', '192.0.2.2'),
+ dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
+ dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'),
dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
]
def checkNotBlocked(self, name, adQuery=False):
self.checkBlocked(name, False, adQuery)
+ def checkCustom(self, qname, qtype, expected):
+ query = dns.message.make_query(qname, qtype, want_dnssec=True)
+ query.flags |= dns.flags.CD
+ res = self.sendUDPQuery(query)
+
+ self.assertRRsetInAnswer(res, expected)
+
+ def checkNoData(self, qname, qtype):
+ query = dns.message.make_query(qname, qtype, want_dnssec=True)
+ query.flags |= dns.flags.CD
+ res = self.sendUDPQuery(query)
+
+ self.assertEqual(len(res.answer), 0)
+
def waitUntilCorrectSerialIsLoaded(self, serial, timeout=5):
global rpzServer
self.checkNotBlocked('c.example.')
self.checkBlocked('d.example.')
- # sixth zone, only e should be blocked
+ # sixth zone, only e should be blocked, f is a local data record
self.waitUntilCorrectSerialIsLoaded(6)
- self.checkRPZStats(6, 1, 2, self._xfrDone)
+ self.checkRPZStats(6, 2, 2, self._xfrDone)
+ self.checkNotBlocked('a.example.')
+ self.checkNotBlocked('b.example.')
+ self.checkNotBlocked('c.example.')
+ self.checkNotBlocked('d.example.')
+ self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'))
+ self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
+ self.checkNoData('e.example.', 'AAAA')
+ self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'))
+
+ # seventh zone, e should only have one A
+ self.waitUntilCorrectSerialIsLoaded(7)
+ self.checkRPZStats(7, 2, 2, self._xfrDone)
self.checkNotBlocked('a.example.')
self.checkNotBlocked('b.example.')
self.checkNotBlocked('c.example.')
self.checkNotBlocked('d.example.')
- self.checkBlocked('e.example.')
+ self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'))
+ self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
+ self.checkNoData('e.example.', 'AAAA')
+ self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'))
# check that the policy is disabled for AD=1 queries
self.checkNotBlocked('e.example.', True)