@@ -1568,6 +1568,95 @@ BOOST_AUTO_TEST_CASE(test_following_cname_chain_with_a)
15681568 BOOST_CHECK_EQUAL (ret[2 ].getContent ()->getZoneRepresentation (), " 192.0.2.2" );
15691569}
15701570
1571+ BOOST_AUTO_TEST_CASE (test_following_cname_chain_with_rpz)
1572+ {
1573+ std::unique_ptr<SyncRes> resolver;
1574+ initSR (resolver);
1575+ resolver->setQNameMinimization (true );
1576+
1577+ primeHints ();
1578+
1579+ const DNSName target (" rpzhit.powerdns.com." );
1580+ const DNSName cnameTargeta (" cname-targeta.powerdns.com" );
1581+ const DNSName cnameTargetb (" cname-targetb.powerdns.com" );
1582+
1583+ resolver->setAsyncCallback ([&](const ComboAddress& address, const DNSName& domain, int /* type */ , bool /* doTCP */ , bool /* sendRDQuery */ , int /* EDNS0Level */ , struct timeval * /* now */ , boost::optional<Netmask>& /* srcmask */ , const ResolveContext& /* context */ , LWResult* res, bool * /* chained */ ) {
1584+ if (isRootServer (address)) {
1585+ setLWResult (res, 0 , false , false , true );
1586+ addRecordToLW (res, domain, QType::NS, " a.gtld-servers.net." , DNSResourceRecord::AUTHORITY, 172800 );
1587+ addRecordToLW (res, " a.gtld-servers.net." , QType::A, " 192.0.2.1" , DNSResourceRecord::ADDITIONAL, 3600 );
1588+ return LWResult::Result::Success;
1589+ }
1590+ if (address == ComboAddress (" 192.0.2.1:53" )) {
1591+
1592+ if (domain == cnameTargeta) {
1593+ setLWResult (res, 0 , true , false , false );
1594+ addRecordToLW (res, cnameTargeta, QType::CNAME, cnameTargetb.toString ());
1595+ return LWResult::Result::Success;
1596+ }
1597+ if (domain == cnameTargetb) {
1598+ setLWResult (res, 0 , true , false , false );
1599+ addRecordToLW (res, domain, QType::A, " 192.0.2.2" , DNSResourceRecord::ANSWER, 10 );
1600+ }
1601+
1602+ return LWResult::Result::Success;
1603+ }
1604+
1605+ return LWResult::Result::Timeout;
1606+ });
1607+
1608+ DNSFilterEngine::Policy pol;
1609+ pol.d_ttl = 600 ;
1610+ pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
1611+ auto customRecord = DNSRecordContent::make (QType::CNAME, QClass::IN, cnameTargeta.toString ());
1612+ std::vector<std::shared_ptr<const DNSRecordContent>> custom = {customRecord};
1613+ pol.setCustom (custom);
1614+ std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
1615+ zone->setName (" Unit test policy 0" );
1616+ zone->addQNameTrigger (target, std::move (pol));
1617+ auto luaconfsCopy = g_luaconfs.getCopy ();
1618+ luaconfsCopy.dfe .clearZones ();
1619+ luaconfsCopy.dfe .addZone (zone);
1620+ g_luaconfs.setState (luaconfsCopy);
1621+
1622+ time_t now = time (nullptr );
1623+
1624+ vector<DNSRecord> ret;
1625+ int res = resolver->beginResolve (target, QType (QType::A), QClass::IN, ret);
1626+ BOOST_CHECK_EQUAL (res, RCode::NoError);
1627+ BOOST_REQUIRE_EQUAL (ret.size (), 3U );
1628+ BOOST_CHECK (ret[0 ].d_type == QType::CNAME);
1629+ BOOST_CHECK_EQUAL (ret[0 ].d_name , target);
1630+ BOOST_CHECK_EQUAL (ret[0 ].getContent ()->getZoneRepresentation (), cnameTargeta.toString ());
1631+ BOOST_CHECK (ret[1 ].d_type == QType::CNAME);
1632+ BOOST_CHECK_EQUAL (ret[1 ].d_name , cnameTargeta);
1633+ BOOST_CHECK_EQUAL (ret[1 ].getContent ()->getZoneRepresentation (), cnameTargetb.toString ());
1634+ BOOST_CHECK (ret[2 ].d_type == QType::A);
1635+ BOOST_CHECK_EQUAL (ret[2 ].d_name , cnameTargetb);
1636+ BOOST_CHECK_EQUAL (ret[2 ].getContent ()->getZoneRepresentation (), " 192.0.2.2" );
1637+
1638+ // Let the final record expire. If an RPZ producing a custom CNAME was hit, we used to not follow
1639+ // the CNAME as aggressively as needed. The symptom being the final record missing from the
1640+ // result.
1641+ resolver->setNow (timeval{now + 20 , 0 });
1642+ resolver->setQNameMinimization (true ); // XXX find out why this is needed
1643+
1644+ ret.clear ();
1645+ resolver->d_appliedPolicy = DNSFilterEngine::Policy ();
1646+ res = resolver->beginResolve (target, QType (QType::A), QClass::IN, ret);
1647+ BOOST_CHECK_EQUAL (res, RCode::NoError);
1648+ BOOST_REQUIRE_EQUAL (ret.size (), 3U );
1649+ BOOST_CHECK (ret[0 ].d_type == QType::CNAME);
1650+ BOOST_CHECK_EQUAL (ret[0 ].d_name , target);
1651+ BOOST_CHECK_EQUAL (ret[0 ].getContent ()->getZoneRepresentation (), cnameTargeta.toString ());
1652+ BOOST_CHECK (ret[1 ].d_type == QType::CNAME);
1653+ BOOST_CHECK_EQUAL (ret[1 ].d_name , cnameTargeta);
1654+ BOOST_CHECK_EQUAL (ret[1 ].getContent ()->getZoneRepresentation (), cnameTargetb.toString ());
1655+ BOOST_CHECK (ret[2 ].d_type == QType::A);
1656+ BOOST_CHECK_EQUAL (ret[2 ].d_name , cnameTargetb);
1657+ BOOST_CHECK_EQUAL (ret[2 ].getContent ()->getZoneRepresentation (), " 192.0.2.2" );
1658+ }
1659+
15711660BOOST_AUTO_TEST_CASE (test_cname_nxdomain)
15721661{
15731662 std::unique_ptr<SyncRes> sr;
0 commit comments