* policyAction: The action taken by the engine
* policyCustom: The CNAME content for the `pdns.policyactions.Custom` response, a string
* policyTTL: The TTL in seconds for the `pdns.policyactions.Custom` response
+* wantsRPZ - A boolean that indicates the use of the Policy Engine, can be set to `false` in `preresolve` to disable RPZ for this query
It also supports the following methods:
}
}
return pol;
-}
+}
+DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const ComboAddress& address) const
+{
+ // cout<<"Got question for nameserver IP "<<address.toString()<<endl;
+ for(const auto& z : d_zones) {
+ if(auto fnd=z.propolNSAddr.lookup(address)) {
+ // cerr<<"Had a hit on the nameserver ("<<address.toString()<<") used to process the query"<<endl;
+ return fnd->second;;
+ }
+ }
+ return Policy{PolicyKind::NoAction, nullptr, "", 0};
+}
DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, const ComboAddress& ca) const
{
d_zones[zone].propolName[n]=pol;
}
+void DNSFilterEngine::addNSIPTrigger(const Netmask& nm, Policy pol, int zone)
+{
+ assureZones(zone);
+ d_zones[zone].propolNSAddr.insert(nm).second = pol;
+}
+
bool DNSFilterEngine::rmClientTrigger(const Netmask& nm, Policy pol, int zone)
{
assureZones(zone);
d_zones[zone].propolName.erase(n); // XXX verify policy matched? =pol;
return true;
}
+
+bool DNSFilterEngine::rmNSIPTrigger(const Netmask& nm, Policy pol, int zone)
+{
+ assureZones(zone);
+ auto& pols = d_zones[zone].propolNSAddr;
+ pols.erase(nm);
+ return true;
+}
void addClientTrigger(const Netmask& nm, Policy pol, int zone=0);
void addQNameTrigger(const DNSName& nm, Policy pol, int zone=0);
void addNSTrigger(const DNSName& dn, Policy pol, int zone=0);
+ void addNSIPTrigger(const Netmask& nm, Policy pol, int zone=0);
void addResponseTrigger(const Netmask& nm, Policy pol, int zone=0);
bool rmClientTrigger(const Netmask& nm, Policy pol, int zone=0);
bool rmQNameTrigger(const DNSName& nm, Policy pol, int zone=0);
bool rmNSTrigger(const DNSName& dn, Policy pol, int zone=0);
+ bool rmNSIPTrigger(const Netmask& nm, Policy pol, int zone=0);
bool rmResponseTrigger(const Netmask& nm, Policy pol, int zone=0);
Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm) const;
Policy getProcessingPolicy(const DNSName& qname) const;
+ Policy getProcessingPolicy(const ComboAddress& address) const;
Policy getPostPolicy(const vector<DNSRecord>& records) const;
size_t size() {
private:
void assureZones(int zone);
struct Zone {
- std::map<DNSName, Policy> qpolName;
- NetmaskTree<Policy> qpolAddr;
- std::map<DNSName, Policy> propolName;
- NetmaskTree<Policy> postpolAddr;
+ std::map<DNSName, Policy> qpolName; // QNAME trigger (RPZ)
+ NetmaskTree<Policy> qpolAddr; // Source address
+ std::map<DNSName, Policy> propolName; // NSDNAME (RPZ)
+ NetmaskTree<Policy> propolNSAddr; // NSIP (RPZ)
+ NetmaskTree<Policy> postpolAddr; // IP trigger (RPZ)
};
vector<Zone> d_zones;
return false;
}
-bool RecursorLua4::preresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable)
+bool RecursorLua4::preresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable, bool* wantsRPZ)
{
return false;
}
d_lw->registerMember("udpAnswer", &DNSQuestion::udpAnswer);
d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
+ d_lw->registerMember("wantsRPZ", &DNSQuestion::wantsRPZ);
d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
d_lw->registerMember("policyName", &DNSFilterEngine::Policy::d_name);
d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
}
-bool RecursorLua4::preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
+bool RecursorLua4::preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable, bool* wantsRPZ)
{
- return genhook(d_preresolve, remote, local, query, qtype, isTcp, res, ednsOpts, tag, appliedPolicy, policyTags, ret, variable);
+ return genhook(d_preresolve, remote, local, query, qtype, isTcp, res, ednsOpts, tag, appliedPolicy, policyTags, ret, variable, wantsRPZ);
}
bool RecursorLua4::nxdomain(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable)
{
- return genhook(d_nxdomain, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable);
+ return genhook(d_nxdomain, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable, 0);
}
bool RecursorLua4::nodata(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable)
{
- return genhook(d_nodata, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable);
+ return genhook(d_nodata, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable, 0);
}
bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
{
- return genhook(d_postresolve, remote, local, query, qtype, isTcp, res, 0, 0, appliedPolicy, policyTags, ret, variable);
+ return genhook(d_postresolve, remote, local, query, qtype, isTcp, res, 0, 0, appliedPolicy, policyTags, ret, variable, 0);
}
bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
{
- return genhook(d_preoutquery, ns, requestor, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, 0);
+ return genhook(d_preoutquery, ns, requestor, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, 0, 0);
}
bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader& dh)
return 0;
}
-bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
+bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable, bool* wantsRPZ)
{
if(!func)
return false;
dq->rcode = ret;
dq->policyTags = policyTags;
dq->appliedPolicy = appliedPolicy;
+ dq->wantsRPZ = wantsRPZ;
bool handled=func(dq);
if(variable) *variable |= dq->variable; // could still be set to indicate this *name* is variable, even if not 'handled'
+ *wantsRPZ = dq->wantsRPZ; // Even if we did not handle the query, RPZ could be disabled
if(handled) {
loop:;
public:
explicit RecursorLua4(const std::string& fname);
~RecursorLua4(); // this is so unique_ptr works with an incomplete type
- bool preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
+ bool preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable, bool* wantsRPZ);
bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable);
bool nodata(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable);
bool postresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
DNSFilterEngine::Policy* appliedPolicy;
std::vector<std::string>* policyTags;
bool isTcp;
+ bool wantsRPZ;
};
typedef std::function<bool(std::shared_ptr<DNSQuestion>)> luacall_t;
luacall_t d_preresolve, d_nxdomain, d_nodata, d_postresolve, d_preoutquery, d_postoutquery;
- bool genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
+ bool genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable, bool* wantsRPZ);
typedef std::function<bool(ComboAddress,ComboAddress, struct dnsheader)> ipfilter_t;
ipfilter_t d_ipfilter;
};
auto luaconfsLocal = g_luaconfs.getLocal();
DNSFilterEngine::Policy appliedPolicy;
+ // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
+ bool wantsRPZ(true);
RecProtoBufMessage pbMessage(RecProtoBufMessage::Response);
#ifdef HAVE_PROTOBUF
if (luaconfsLocal->protobufServer) {
appliedPolicy = dfepol;
// if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
- if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, dc->d_ednsOpts.empty() ? 0 : &dc->d_ednsOpts, dc->d_tag, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer)) {
-
- switch(appliedPolicy.d_kind) {
- case DNSFilterEngine::PolicyKind::NoAction:
- break;
- case DNSFilterEngine::PolicyKind::Drop:
- g_stats.policyDrops++;
- g_stats.policyResults[appliedPolicy.d_kind]++;
- delete dc;
- dc=0;
- return;
- case DNSFilterEngine::PolicyKind::NXDOMAIN:
- g_stats.policyResults[appliedPolicy.d_kind]++;
- res=RCode::NXDomain;
- goto haveAnswer;
- case DNSFilterEngine::PolicyKind::NODATA:
- g_stats.policyResults[appliedPolicy.d_kind]++;
- res=RCode::NoError;
- goto haveAnswer;
- case DNSFilterEngine::PolicyKind::Custom:
- g_stats.policyResults[appliedPolicy.d_kind]++;
- res=RCode::NoError;
- spoofed.d_name=dc->d_mdp.d_qname;
- spoofed.d_type=appliedPolicy.d_custom->getType();
- spoofed.d_ttl = appliedPolicy.d_ttl;
- spoofed.d_class = 1;
- spoofed.d_content = appliedPolicy.d_custom;
- spoofed.d_place = DNSResourceRecord::ANSWER;
- ret.push_back(spoofed);
- goto haveAnswer;
- case DNSFilterEngine::PolicyKind::Truncate:
- if(!dc->d_tcp) {
+ if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, dc->d_ednsOpts.empty() ? 0 : &dc->d_ednsOpts, dc->d_tag, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer, &wantsRPZ)) {
+
+ sr.d_wantsRPZ = wantsRPZ;
+ if(wantsRPZ) {
+ switch(appliedPolicy.d_kind) {
+ case DNSFilterEngine::PolicyKind::NoAction:
+ break;
+ case DNSFilterEngine::PolicyKind::Drop:
+ g_stats.policyDrops++;
g_stats.policyResults[appliedPolicy.d_kind]++;
- res=RCode::NoError;
- pw.getHeader()->tc=1;
+ delete dc;
+ dc=0;
+ return;
+ case DNSFilterEngine::PolicyKind::NXDOMAIN:
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ res=RCode::NXDomain;
goto haveAnswer;
- }
- break;
+ case DNSFilterEngine::PolicyKind::NODATA:
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ res=RCode::NoError;
+ goto haveAnswer;
+ case DNSFilterEngine::PolicyKind::Custom:
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ res=RCode::NoError;
+ spoofed.d_name=dc->d_mdp.d_qname;
+ spoofed.d_type=appliedPolicy.d_custom->getType();
+ spoofed.d_ttl = appliedPolicy.d_ttl;
+ spoofed.d_class = 1;
+ spoofed.d_content = appliedPolicy.d_custom;
+ spoofed.d_place = DNSResourceRecord::ANSWER;
+ ret.push_back(spoofed);
+ goto haveAnswer;
+ case DNSFilterEngine::PolicyKind::Truncate:
+ if(!dc->d_tcp) {
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ res=RCode::NoError;
+ pw.getHeader()->tc=1;
+ goto haveAnswer;
+ }
+ break;
+ }
}
- // Query got not handled for Policy reasons, now actually go out to find an answer
+ // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
try {
res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
shouldNotValidate = sr.wasOutOfBand();
res = RCode::ServFail;
}
- dfepol = luaconfsLocal->dfe.getPostPolicy(ret);
- appliedPolicy = dfepol;
+ // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
+ if (res == -2) { // XXX This block should be macro'd, it is repeated post-resolve.
+ appliedPolicy = sr.d_appliedPolicy;
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ switch(appliedPolicy.d_kind) {
+ case DNSFilterEngine::PolicyKind::NoAction: // This can never happen
+ throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
+ case DNSFilterEngine::PolicyKind::Drop:
+ g_stats.policyDrops++;
+ delete dc;
+ dc=0;
+ return;
+ case DNSFilterEngine::PolicyKind::NXDOMAIN:
+ ret.clear();
+ res=RCode::NXDomain;
+ goto haveAnswer;
+
+ case DNSFilterEngine::PolicyKind::NODATA:
+ ret.clear();
+ res=RCode::NoError;
+ goto haveAnswer;
+
+ case DNSFilterEngine::PolicyKind::Truncate:
+ if(!dc->d_tcp) {
+ ret.clear();
+ res=RCode::NoError;
+ pw.getHeader()->tc=1;
+ goto haveAnswer;
+ }
+ break;
+
+ case DNSFilterEngine::PolicyKind::Custom:
+ ret.clear();
+ res=RCode::NoError;
+ spoofed.d_name=dc->d_mdp.d_qname;
+ spoofed.d_type=appliedPolicy.d_custom->getType();
+ spoofed.d_ttl = appliedPolicy.d_ttl;
+ spoofed.d_class = 1;
+ spoofed.d_content = appliedPolicy.d_custom;
+ spoofed.d_place = DNSResourceRecord::ANSWER;
+ ret.push_back(spoofed);
+ goto haveAnswer;
+ }
+ }
+
+ if (wantsRPZ) {
+ dfepol = luaconfsLocal->dfe.getPostPolicy(ret);
+ appliedPolicy = dfepol;
+ }
if(t_pdl->get()) {
if(res == RCode::NoError) {
(*t_pdl)->postresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer);
}
- g_stats.policyResults[appliedPolicy.d_kind]++;
- switch(appliedPolicy.d_kind) {
- case DNSFilterEngine::PolicyKind::NoAction:
- break;
- case DNSFilterEngine::PolicyKind::Drop:
- g_stats.policyDrops++;
- delete dc;
- dc=0;
- return;
- case DNSFilterEngine::PolicyKind::NXDOMAIN:
- ret.clear();
- res=RCode::NXDomain;
- goto haveAnswer;
-
- case DNSFilterEngine::PolicyKind::NODATA:
- ret.clear();
- res=RCode::NoError;
- goto haveAnswer;
-
- case DNSFilterEngine::PolicyKind::Truncate:
- if(!dc->d_tcp) {
- ret.clear();
- res=RCode::NoError;
- pw.getHeader()->tc=1;
- goto haveAnswer;
- }
- break;
-
- case DNSFilterEngine::PolicyKind::Custom:
- ret.clear();
- res=RCode::NoError;
- spoofed.d_name=dc->d_mdp.d_qname;
- spoofed.d_type=appliedPolicy.d_custom->getType();
- spoofed.d_ttl = appliedPolicy.d_ttl;
- spoofed.d_class = 1;
- spoofed.d_content = appliedPolicy.d_custom;
- spoofed.d_place = DNSResourceRecord::ANSWER;
- ret.push_back(spoofed);
- goto haveAnswer;
+ if (wantsRPZ) { //XXX This block is repeated, see above
+ g_stats.policyResults[appliedPolicy.d_kind]++;
+ switch(appliedPolicy.d_kind) {
+ case DNSFilterEngine::PolicyKind::NoAction:
+ break;
+ case DNSFilterEngine::PolicyKind::Drop:
+ g_stats.policyDrops++;
+ delete dc;
+ dc=0;
+ return;
+ case DNSFilterEngine::PolicyKind::NXDOMAIN:
+ ret.clear();
+ res=RCode::NXDomain;
+ goto haveAnswer;
+
+ case DNSFilterEngine::PolicyKind::NODATA:
+ ret.clear();
+ res=RCode::NoError;
+ goto haveAnswer;
+
+ case DNSFilterEngine::PolicyKind::Truncate:
+ if(!dc->d_tcp) {
+ ret.clear();
+ res=RCode::NoError;
+ pw.getHeader()->tc=1;
+ goto haveAnswer;
+ }
+ break;
+
+ case DNSFilterEngine::PolicyKind::Custom:
+ ret.clear();
+ res=RCode::NoError;
+ spoofed.d_name=dc->d_mdp.d_qname;
+ spoofed.d_type=appliedPolicy.d_custom->getType();
+ spoofed.d_ttl = appliedPolicy.d_ttl;
+ spoofed.d_class = 1;
+ spoofed.d_content = appliedPolicy.d_custom;
+ spoofed.d_place = DNSResourceRecord::ANSWER;
+ ret.push_back(spoofed);
+ goto haveAnswer;
+ }
}
}
haveAnswer:;
static Netmask makeNetmaskFromRPZ(const DNSName& name)
{
auto parts = name.getRawLabels();
- if(parts.size() < 5)
+ /*
+ * why 2?, the minimally valid IPv6 address that can be encoded in an RPZ is
+ * $NETMASK.zz (::/$NETMASK)
+ * Terrible right?
+ */
+ if(parts.size() < 2 || parts.size() > 9)
throw PDNSException("Invalid IP address in RPZ: "+name.toString());
- return Netmask(parts[4]+"."+parts[3]+"."+parts[2]+"."+parts[1]+"/"+parts[0]);
+
+ bool isV6 = (stoi(parts[0]) > 32);
+ bool hadZZ = false;
+
+ for (auto &part : parts) {
+ // Check if we have an IPv4 octet
+ for (auto c : part)
+ if (!isdigit(c))
+ isV6 = true;
+
+ if (pdns_iequals(part,"zz")) {
+ if (hadZZ)
+ throw PDNSException("more than one 'zz' label found in RPZ name"+name.toString());
+ part = "";
+ isV6 = true;
+ hadZZ = true;
+ }
+ }
+
+ if (isV6 && parts.size() < 9 && !hadZZ)
+ throw PDNSException("No 'zz' label found in an IPv6 RPZ name shorter than 9 elements: "+name.toString());
+
+ if (parts.size() == 5 && !isV6)
+ return Netmask(parts[4]+"."+parts[3]+"."+parts[2]+"."+parts[1]+"/"+parts[0]);
+
+ string v6;
+
+ for (uint8_t i = parts.size()-1 ; i > 0; i--) {
+ v6 += parts[i];
+ if (parts[i] == "" && i == 1 && i == parts.size()-1)
+ v6+= "::";
+ if (parts[i] == "" && i != parts.size()-1)
+ v6+= ":";
+ if (parts[i] != "" && i != 1)
+ v6 += ":";
+ }
+ v6 += "/" + parts[0];
+
+ return Netmask(v6);
}
void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, const std::string& polName, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, int place)
else
target.rmNSTrigger(filt, pol);
} else if(dr.d_name.isPartOf(rpzClientIP)) {
-
- auto nm=makeNetmaskFromRPZ(dr.d_name);
-
+ DNSName filt=dr.d_name.makeRelative(rpzClientIP);
+ auto nm=makeNetmaskFromRPZ(filt);
if(addOrRemove)
target.addClientTrigger(nm, pol);
else
} else if(dr.d_name.isPartOf(rpzIP)) {
// cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
- auto nm=makeNetmaskFromRPZ(dr.d_name);
+ DNSName filt=dr.d_name.makeRelative(rpzIP);
+ auto nm=makeNetmaskFromRPZ(filt);
if(addOrRemove)
target.addResponseTrigger(nm, pol);
else
target.rmResponseTrigger(nm, pol);
} else if(dr.d_name.isPartOf(rpzNSIP)) {
- cerr<<"Should apply to nameserver IP address policy HAVE NOTHING HERE"<<endl;
-
+ DNSName filt=dr.d_name.makeRelative(rpzNSIP);
+ auto nm=makeNetmaskFromRPZ(filt);
+ if(addOrRemove)
+ target.addNSIPTrigger(nm, pol);
+ else
+ target.rmNSIPTrigger(nm, pol);
} else {
if(addOrRemove)
target.addQNameTrigger(dr.d_name, pol);
prefix=d_prefix;
prefix.append(depth, ' ');
}
-
+
LOG(prefix<<qname<<": Wants "<< (d_doDNSSEC ? "" : "NO ") << "DNSSEC processing in query for "<<qtype.getName()<<endl);
int res=0;
LOG(prefix<<qname<<": failed (res="<<res<<")"<<endl);
;
+
+ if (res == -2)
+ return res;
+
return res<0 ? RCode::ServFail : res;
}
}
}
-/** returns -1 in case of no results, rcode otherwise */
+/** returns:
+ * -1 in case of no results
+ * -2 when a FilterEngine Policy was hit
+ * rcode otherwise
+ */
int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
vector<DNSRecord>&ret,
int depth, set<GetBestNSAnswer>&beenthere)
prefix.append(depth, ' ');
}
- LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact"<<endl);
+ LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
+
+ if(d_wantsRPZ) {
+ for (auto const &ns : nameservers) {
+ d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(ns.first);
+ if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
+ LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<d_appliedPolicy.d_name<<"'"<<endl);
+ return -2;
+ }
+
+ // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
+ for (auto const &address : ns.second.first) {
+ d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(address);
+ if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
+ LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<d_appliedPolicy.d_name<<"'"<<endl);
+ return -2;
+ }
+ }
+ }
+ }
+
+ LOG(endl);
for(;;) { // we may get more specific nameservers
vector<DNSName > rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
if(!tns->empty()) {
LOG(prefix<<qname<<": Trying to resolve NS '"<<*tns<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
}
- //
- // XXX NEED TO HANDLE OTHER POLICY KINDS HERE!
- if(g_luaconfs.getLocal()->dfe.getProcessingPolicy(*tns).d_kind != DNSFilterEngine::PolicyKind::NoAction) {
- g_stats.policyResults[g_luaconfs.getLocal()->dfe.getProcessingPolicy(*tns).d_kind]++;
- throw ImmediateServFailException("Dropped because of policy");
- }
if(tns->empty()) {
LOG(prefix<<qname<<": Domain has hardcoded nameserver");
continue;
}
else {
+ bool hitPolicy{false};
LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<*tns<<" to: ");
for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
if(remoteIP != remoteIPs.begin()) {
LOG(", ");
}
LOG(remoteIP->toString());
+ if (d_wantsRPZ) {
+ d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(*remoteIP);
+ if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
+ hitPolicy = true;
+ LOG(" (blocked by RPZ policy '"+d_appliedPolicy.d_name+"')");
+ }
+ }
}
LOG(endl);
-
+ if (hitPolicy) //implies d_wantsRPZ
+ return -2;
}
for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
return 0;
}
else if(realreferral) {
- LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, looping to them"<<endl);
+ LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
if(sawDS) {
t_sstorage->dnssecmap[newauth]=true;
/* for(const auto& e : t_sstorage->dnssecmap)
auth=newauth;
nameservers.clear();
- for (auto const &nameserver : nsset)
+ for (auto const &nameserver : nsset) {
+ if (d_wantsRPZ) {
+ d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(nameserver);
+ if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
+ LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<d_appliedPolicy.d_name<<"'"<<endl);
+ return -2;
+ }
+ }
nameservers.insert({nameserver, {{}, false}});
+ }
+ LOG("looping to them"<<endl);
break;
}
else if(!tns->empty()) { // means: not OOB, OOB == empty
bool d_wasVariable{false};
bool d_wasOutOfBand{false};
+ bool d_wantsRPZ{true};
+ DNSFilterEngine::Policy d_appliedPolicy{DNSFilterEngine::PolicyKind::NoAction, nullptr, "", 0};
typedef multi_index_container <
NegCacheEntry,