#include "dnsname.hh"
#include "dnsparser.hh"
#include "dnsrecords.hh"
+#include "iputils.hh"
#include "qtype.hh"
#include <boost/smart_ptr/make_shared_array.hpp>
#ifdef HAVE_CONFIG_H
::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
::arg().set("max-include-depth", "Maximum nested $INCLUDE depth when loading a zone from a file")="20";
::arg().setSwitch("upgrade-unknown-types","Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up")="no";
+ ::arg().setSwitch("views", "Enable views (variants) of zones, for backends which support them") = "no";
::arg().laxFile(configname);
if(!::arg()["load-modules"].empty()) {
cerr << "Zone '" << zone << "' was not created." << endl;
return EXIT_FAILURE;
}
+ if (zone.hasVariant() && (B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ cerr << "Zone '" << zone << "' was not created." << endl;
+ return EXIT_FAILURE;
+ }
cerr<<"Creating '"<<zone<<"'"<<endl;
B.createDomain(zone, DomainInfo::Native, vector<ComboAddress>(), "");
cerr << "Zone '" << zone << "' was not created." << endl;
return EXIT_FAILURE;
}
+ if (zone.hasVariant() && (B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ cerr << "Zone '" << zone << "' was not created." << endl;
+ return EXIT_FAILURE;
+ }
DNSResourceRecord rr;
rr.qname = zone.operator const DNSName&();
cerr<<"Creating empty zone '"<<zone<<"'"<<endl;
B.createDomain(zone, DomainInfo::Native, vector<ComboAddress>(), "");
if(!B.getDomainInfo(zone, di)) {
- cerr << "Zone '" << zone << "' was not created!" << endl;
+ cerr << "Zone '" << zone << "' was not created." << endl;
return EXIT_FAILURE;
}
vector<DomainInfo> domains;
B.getAllDomains(&domains, false, g_verbose);
+ // Sort results, so that domains which have variants will appear
+ // grouped in the output.
+ std::sort(domains.begin(), domains.end());
+
int count = 0;
for (const auto& di: domains) {
if (di.kind == kindFilter || kindFilter == -1) {
}
if (!exportDS) {
cout<<"This is a "<<DomainInfo::getKindString(di.kind)<<" zone"<<endl;
+ auto variant = di.zone.getVariant();
+ if (!variant.empty()) {
+ cout<<"Variant: " << variant << endl;
+ }
if (di.isPrimaryType()) {
cout<<"Last SOA serial number we notified: "<<di.notified_serial<<" ";
SOAData sd;
cerr << "Zone '" << zone << "' was not created." << endl;
return EXIT_FAILURE;
}
+ if (zone.hasVariant() && (B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ cerr << "Zone '" << zone << "' was not created." << endl;
+ return EXIT_FAILURE;
+ }
vector<ComboAddress> primaries;
for (unsigned i=2; i < cmds.size(); i++) {
primaries.emplace_back(cmds.at(i), 53);
cerr << "Creating secondary zone '" << zone << "', with primaries '" << comboAddressVecToString(primaries) << "'" << endl;
B.createDomain(zone, DomainInfo::Secondary, primaries, "");
if(!B.getDomainInfo(zone, di)) {
- cerr << "Zone '" << zone << "' was not created!" << endl;
+ cerr << "Zone '" << zone << "' was not created." << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
DNSResourceRecord rr; // NOLINT(readability-identifier-length)
cout<<"Processing '"<<di.zone<<"'"<<endl;
// create zone
+ if (di.zone.hasVariant() && (tgt->getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "Target backend does not support views." << endl;
+ throw PDNSException("Failed to create zone");
+ }
if (!tgt->createDomain(di.zone, di.kind, di.primaries, di.account)) {
- throw PDNSException("Failed to create zone");
+ throw PDNSException("Failed to create zone");
}
if (!tgt->getDomainInfo(di.zone, di_new)) {
throw PDNSException("Failed to create zone");
type = DNSRecordContent::TypeToNumber(cmds.at(3));
}
- DNSName name{cmds.at(2)};
+ ZoneName name{cmds.at(2)};
+ domainid_t domain_id{UnknownDomainID};
+
+ if (name.hasVariant()) {
+ ZoneName zone(name);
+ do {
+ SOAData soa;
+ if (matchingBackend->getSOA(zone, UnknownDomainID, soa)) {
+ domain_id = soa.domain_id;
+ break;
+ }
+ } while (zone.chopOff());
+ if (domain_id == UnknownDomainID) {
+ cerr << "Backend found no matching zone" << endl;
+ return 1;
+ }
+ }
DNSPacket queryPacket(true);
Netmask clientNetmask;
queryPacket.setRealRemote(clientNetmask);
}
- matchingBackend->lookup(type, name, -1, &queryPacket);
+ matchingBackend->lookup(type, name.operator const DNSName&(), domain_id, &queryPacket);
bool found = false;
DNSZoneRecord resultZoneRecord;
return 0;
}
+static int listView(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.size() != 2) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ vector<ZoneName> ret;
+ B.viewListZones(cmds.at(1), ret);
+
+ for (const auto& zone : ret) {
+ cout << zone << endl;
+ }
+ return 0;
+}
+
+static int listViews(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.size() != 1) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ vector<string> ret;
+ B.viewList(ret);
+
+ for (const auto& view : ret) {
+ cout << view << endl;
+ }
+ return 0;
+}
+
+static int viewAddZone(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.size() < 3) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ string view{cmds.at(1)};
+ ZoneName zone{cmds.at(2)};
+ if (!B.viewAddZone(view, zone)) {
+ cerr<<"Operation failed."<<endl;
+ return 1;
+ }
+ return 0;
+}
+
+static int viewDelZone(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.size() < 3) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ string view{cmds.at(1)};
+ ZoneName zone{cmds.at(2)};
+ if (!B.viewDelZone(view, zone)) {
+ cerr<<"Operation failed."<<endl;
+ return 1;
+ }
+ return 0;
+}
+
+static int listNetwork(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.empty()) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ vector<pair<Netmask, string> > ret;
+
+ B.networkList(ret);
+
+ for (auto &[net, view] : ret) {
+ cout<<net.toString()<<"\t"<<view<<endl; // FIXME: this prints "invalid" when there is no match
+ }
+ return 0;
+}
+
+static int setNetwork(vector<string>& cmds, const std::string_view synopsis)
+{
+ if (cmds.size() < 2) {
+ return usage(synopsis);
+ }
+
+ UtilBackend B("default"); //NOLINT(readability-identifier-length)
+
+ Netmask net{cmds.at(1)};
+ string view{};
+ if (cmds.size() > 2) {
+ view = cmds.at(2);
+ }
+ if (!B.networkSet(net, view)) {
+ cerr<<"Operation failed."<<endl;
+ return 1;
+ }
+ return 0;
+}
+
enum commandGroup {
GROUP_AUTOPRIMARY,
GROUP_CATALOG,
GROUP_NSEC3,
GROUP_TSIGKEY,
GROUP_ZONEKEY,
+ GROUP_VIEWS,
GROUP_OTHER,
GROUP_LAST,
GROUP_FIRST = GROUP_AUTOPRIMARY,
"NSEC3",
"TSIG key",
"Zone key",
+ "Views",
"Other"
};
{"list-member-zones", {true, listMemberZones, GROUP_ZONE,
"list-member-zones CATALOG",
"\tList all members of catalog zone CATALOG"}},
+ {"list-networks", {true, listNetwork, GROUP_VIEWS,
+ "list-networks",
+ "\tList all defined networks with their chosen views"}},
{"list-tsig-keys", {true, listTSIGKeys, GROUP_TSIGKEY,
"list-tsig-keys",
"\tList all TSIG keys"}},
+ {"list-view", {true, listView, GROUP_VIEWS,
+ "list-view VIEW",
+ "\tList all zones within VIEW"}},
+ {"list-views", {true, listViews, GROUP_VIEWS,
+ "list-view",
+ "\tList all view names"}},
{"list-zone", {true, listZone, GROUP_ZONE,
"list-zone ZONE",
"\tList zone contents"}},
"set-meta ZONE KIND [VALUE...]",
"\tSet zone metadata, replacing all existing records of KIND, optionally\n"
"\tproviding a value. An omitted value clears the metadata"}},
+ {"set-network", {true, setNetwork, GROUP_VIEWS,
+ "set-network NET [VIEW]",
+ "\tSet the view for a network, or delete if no view argument."}},
{"set-nsec3", {true, setNsec3, GROUP_NSEC3,
"set-nsec3 ZONE ['PARAMS' [narrow]]",
"\tEnable NSEC3 with PARAMS (default: '1 0 0 -'). Optionally narrow"}},
"\tDisable sending CDS responses for ZONE"}},
{"verify-crypto", {true, verifyCrypto, GROUP_OTHER,
"verify-crypto FILENAME", ""}}, // TODO: short help line
+ {"view-add-zone", {true, viewAddZone, GROUP_VIEWS,
+ "view-add-zone VIEW ZONE..VARIANT",
+ "\tAdd a zone variant to a view"}},
+ {"view-del-zone", {true, viewDelZone, GROUP_VIEWS,
+ "view-del-zone VIEW ZONE..VARIANT",
+ "\tRemove a zone variant from a view"}},
{"zonemd-verify-file", {true, zonemdVerifyFile, GROUP_ZONE,
"zonemd-verify-file ZONE FILENAME",
"\tValidate ZONEMD for ZONE"}}