From 486210b80662f9d87050283bd6d0e81f0152140b Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Thu, 3 Mar 2022 11:42:58 +0100 Subject: [PATCH] auth /zones/example.com.?rrset_name=www.example.com.&rrset_type=A --- .../swagger/authoritative-api-swagger.yaml | 8 ++ pdns/ws-auth.cc | 12 ++- regression-tests.api/test_Zones.py | 92 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/docs/http-api/swagger/authoritative-api-swagger.yaml b/docs/http-api/swagger/authoritative-api-swagger.yaml index 17a85031e2..709a7f0ec7 100644 --- a/docs/http-api/swagger/authoritative-api-swagger.yaml +++ b/docs/http-api/swagger/authoritative-api-swagger.yaml @@ -188,6 +188,14 @@ paths: description: '“true” (default) or “false”, whether to include the “rrsets” in the response Zone object.' type: boolean default: true + - name: rrset_name + in: query + description: Limit output to RRsets for this name. + type: string + - name: rrset_type + in: query + description: Limit output to the RRset of this type. Can only be used together with rrset_name. + type: string responses: '200': description: A Zone diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index a22117af45..1aeee96d9e 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -402,7 +402,17 @@ static void fillZone(UeberBackend& B, const DNSName& zonename, HttpResponse* res // load all records + sort { DNSResourceRecord rr; - di.backend->list(zonename, di.id, true); // incl. disabled + if (req->getvars.count("rrset_name") == 0) { + di.backend->list(zonename, di.id, true); // incl. disabled + } else { + QType qt; + if (req->getvars.count("rrset_type") == 0) { + qt = QType::ANY; + } else { + qt = req->getvars["rrset_type"]; + } + di.backend->lookup(qt, DNSName(req->getvars["rrset_name"]), di.id); + } while(di.backend->get(rr)) { if (!rr.qtype.getCode()) continue; // skip empty non-terminals diff --git a/regression-tests.api/test_Zones.py b/regression-tests.api/test_Zones.py index bd12e81bc8..d9291f5c2d 100644 --- a/regression-tests.api/test_Zones.py +++ b/regression-tests.api/test_Zones.py @@ -1,5 +1,6 @@ from __future__ import print_function import json +import operator import time import unittest from copy import deepcopy @@ -731,6 +732,97 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin): self.assertIn(k, data) self.assertEqual(data['name'], 'example.com.') + def test_get_zone_rrset(self): + rz = self.session.get(self.url("/api/v1/servers/localhost/zones")) + domains = rz.json() + example_com = [domain for domain in domains if domain['name'] == u'example.com.'][0] + + # verify single record from name that has a single record + r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + example_com['id'] + "?rrset_name=host-18000.example.com.")) + self.assert_success_json(r) + data = r.json() + for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'): + self.assertIn(k, data) + self.assertEqual(data['rrsets'], + [ + { + 'comments': [], + 'name': 'host-18000.example.com.', + 'records': + [ + { + 'content': '192.168.1.80', + 'disabled': False + } + ], + 'ttl': 120, + 'type': 'A' + } + ] + ) + + # verify two RRsets from a name that has two types with one record each + powerdnssec_org = [domain for domain in domains if domain['name'] == u'powerdnssec.org.'][0] + r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + powerdnssec_org['id'] + "?rrset_name=localhost.powerdnssec.org.")) + self.assert_success_json(r) + data = r.json() + for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'): + self.assertIn(k, data) + self.assertEqual(sorted(data['rrsets'], key=operator.itemgetter('type')), + [ + { + 'comments': [], + 'name': 'localhost.powerdnssec.org.', + 'records': + [ + { + 'content': '127.0.0.1', + 'disabled': False + } + ], + 'ttl': 3600, + 'type': 'A' + }, + { + 'comments': [], + 'name': 'localhost.powerdnssec.org.', + 'records': + [ + { + 'content': '::1', + 'disabled': False + } + ], + 'ttl': 3600, + 'type': 'AAAA' + }, + ] + ) + + # verify one RRset with one record from a name that has two, then filtered by type + r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + powerdnssec_org['id'] + "?rrset_name=localhost.powerdnssec.org.&rrset_type=AAAA")) + self.assert_success_json(r) + data = r.json() + for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'): + self.assertIn(k, data) + self.assertEqual(data['rrsets'], + [ + { + 'comments': [], + 'name': 'localhost.powerdnssec.org.', + 'records': + [ + { + 'content': '::1', + 'disabled': False + } + ], + 'ttl': 3600, + 'type': 'AAAA' + } + ] + ) + def test_import_zone_broken(self): payload = { 'name': 'powerdns-broken.com', -- 2.47.2