diff --git a/pdns/filterpo.cc b/pdns/filterpo.cc index b80446a39c93..e9dcff35f2ed 100644 --- a/pdns/filterpo.cc +++ b/pdns/filterpo.cc @@ -244,3 +244,31 @@ bool DNSFilterEngine::rmNSIPTrigger(const Netmask& nm, Policy pol, size_t zone) pols.erase(nm); return true; } + +DNSRecord DNSFilterEngine::Policy::getCustomRecord(const DNSName& qname) 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; + + if (result.d_type == QType::CNAME) { + const auto content = std::dynamic_pointer_cast(d_custom); + if (content) { + DNSName target = content->getTarget(); + if (target.isWildcard()) { + target.chopOff(); + result.d_content = std::make_shared((qname + target).toString()); + } + } + } + + return result; +} diff --git a/pdns/filterpo.hh b/pdns/filterpo.hh index 018cb7d77f1d..3537e6725052 100644 --- a/pdns/filterpo.hh +++ b/pdns/filterpo.hh @@ -74,6 +74,7 @@ public: { return d_kind == rhs.d_kind; // XXX check d_custom too! } + DNSRecord getCustomRecord(const DNSName& qname) const; PolicyKind d_kind; std::shared_ptr d_custom; std::shared_ptr d_name; diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index aab112d1752e..e659c9692516 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -829,12 +829,7 @@ void startDoResolve(void *p) 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; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); ret.push_back(spoofed); handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); goto haveAnswer; @@ -894,12 +889,7 @@ void startDoResolve(void *p) 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; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); ret.push_back(spoofed); handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); goto haveAnswer; @@ -959,12 +949,7 @@ void startDoResolve(void *p) 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; + spoofed=appliedPolicy.getCustomRecord(dc->d_mdp.d_qname); ret.push_back(spoofed); handleRPZCustom(spoofed, QType(dc->d_mdp.d_qtype), sr, res, ret); goto haveAnswer; diff --git a/regression-tests.recursor/RPZ/command b/regression-tests.recursor/RPZ/command index 783f62e3fa80..951dc3ca26da 100755 --- a/regression-tests.recursor/RPZ/command +++ b/regression-tests.recursor/RPZ/command @@ -16,3 +16,5 @@ echo "==> www.hijackme.example.net is served on ns.hijackme.example.net, which s $SDIG $nameserver 5301 www.hijackme.example.net a recurse 2>&1 echo "==> host.lowercase-outgoing.example.net is served on ns.lowercase-outgoing.example.net, blocked by NS IP rule" $SDIG $nameserver 5301 host.lowercase-outgoing.example.net a recurse 2>&1 +echo "==> echo-me.wildcard-target.example.net is an RPZ wildcard target" +$SDIG $nameserver 5301 echo-me.wildcard-target.example.net a recurse 2>&1 diff --git a/regression-tests.recursor/RPZ/expected_result b/regression-tests.recursor/RPZ/expected_result index baf59124e7fd..dc5a89fe431d 100644 --- a/regression-tests.recursor/RPZ/expected_result +++ b/regression-tests.recursor/RPZ/expected_result @@ -28,3 +28,7 @@ Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0 ==> host.lowercase-outgoing.example.net is served on ns.lowercase-outgoing.example.net, blocked by NS IP rule Reply to question for qname='host.lowercase-outgoing.example.net.', qtype=A Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0 +==> echo-me.wildcard-target.example.net is an RPZ wildcard target +Reply to question for qname='echo-me.wildcard-target.example.net.', qtype=A +Rcode: 3 (Non-Existent domain), RD: 1, QR: 1, TC: 0, AA: 0, opcode: 0 +0 echo-me.wildcard-target.example.net. IN CNAME 0 echo-me.wildcard-target.example.net.walled-garden.example.net. diff --git a/regression-tests.recursor/config.sh b/regression-tests.recursor/config.sh index 6cacd01492dd..670d9a48a9b9 100755 --- a/regression-tests.recursor/config.sh +++ b/regression-tests.recursor/config.sh @@ -570,6 +570,7 @@ www.example.net CNAME www2.example.net. ; Local-Data Action www3.example.net CNAME www4.example.net. ; Local-Data Action (to be changed in preresolve) www5.example.net A 192.0.2.15 ; Override www5.example.net. trillian.example.net CNAME . ; NXDOMAIN on apex, allows all sub-names (#4086) +*.wildcard-target.example.net CNAME *.walled-garden.example.net. ; Special form of Local Data: a CNAME RR with a wildcarded target name 32.4.2.0.192.rpz-ip CNAME rpz-drop. ; www4.example.net resolves to 192.0.2.4, drop A responses with that IP