Only one variant per zone may appear in a view; setting a new zone variant will
replace the previous one in the view.
+View names are case-sensitive and may be composed of letters, digits, spaces,
+as well as `-` (dash), `.` (dot) and `_` (underscore). They are not allowed to
+start with a dot or a space.
+
Resolution Algorithm
--------------------
namespace Check
{
+bool validateViewName(std::string_view name, std::string& error)
+{
+ if (name.empty()) {
+ error = "Empty view names are not allowed";
+ return false;
+ }
+
+ if (auto pos = name.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 _-."); pos != std::string_view::npos) {
+ error = std::string("View name contains forbidden character '") + name[pos] + "' at position " + std::to_string(pos);
+ return false;
+ }
+
+ if (name[0] == '.') {
+ error = "View names are not allowed to start with a dot";
+ return false;
+ }
+
+ if (name[0] == ' ') {
+ error = "View names are not allowed to start with a space";
+ return false;
+ }
+
+ return true;
+}
+
void checkRRSet(const vector<DNSResourceRecord>& oldrrs, vector<DNSResourceRecord>& allrrs, const ZoneName& zone, vector<pair<DNSResourceRecord, string>>& errors)
{
// QTypes that MUST NOT have multiple records of the same type in a given RRset.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+// These validation/verification routines are used by both pdnsutil and
+// the pdns_server REST API.
+// They build error messages, if any, into an object provided by the caller
+// (preferrably a container if it makes sense to report multiple errors);
+// it's up to each caller to decide how to report such errors.
+
namespace Check
{
+// Validate a view name. Although view names never appear on the wire, we
+// restrict them to [a-zA-Z0-9-_. ], with empty names or names with leading
+// whitespace or a leading dot forbidden.
+bool validateViewName(std::string_view name, std::string& error);
+
// Returns the list of errors found for new records which violate RRset
// constraints.
// NOTE: sorts records in-place.
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ return 1;
+ }
+
vector<ZoneName> ret;
B.viewListZones(cmds.at(0), ret);
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ // Don't complain about the lack of view support in this case, but
+ // don't list anything either.
+ return 0;
+ }
+
vector<string> ret;
B.viewList(ret);
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ return 1;
+ }
+
string view{cmds.at(0)};
+ string error;
+ if (!Check::validateViewName(view, error)) {
+ cerr << error << "." << endl;
+ return 1;
+ }
ZoneName zone{cmds.at(1)};
if (!B.viewAddZone(view, zone)) {
cerr<<"Operation failed."<<endl;
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ return 1;
+ }
+
string view{cmds.at(0)};
+ string error;
+ if (!Check::validateViewName(view, error)) {
+ cerr << error << "." << endl;
+ return 1;
+ }
ZoneName zone{cmds.at(1)};
if (!B.viewDelZone(view, zone)) {
cerr<<"Operation failed."<<endl;
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ return 1;
+ }
+
vector<pair<Netmask, string> > ret;
B.networkList(ret);
UtilBackend B("default"); //NOLINT(readability-identifier-length)
+ if ((B.getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
+ cerr << "None of the configured backends support views." << endl;
+ return 1;
+ }
+
Netmask net{cmds.at(0)};
string view{};
if (cmds.size() > 1) {
throw ApiException("Zone " + zonename.toString() + " does not exist");
}
std::string view{req->parameters["view"]};
+ std::string error;
+ if (!Check::validateViewName(view, error)) {
+ throw ApiException(error);
+ }
if (!domainInfo.backend->viewAddZone(view, zonename)) {
throw ApiException("Failed to add " + zonename.toString() + " to view " + view);
{
ZoneData zoneData{req};
std::string view{req->parameters["view"]};
+ std::string error;
+ if (!Check::validateViewName(view, error)) {
+ throw ApiException(error);
+ }
if (!zoneData.domainInfo.backend->viewDelZone(view, zoneData.zoneName)) {
throw ApiException("Failed to remove " + zoneData.zoneName.toString() + " from view " + view);
-Operation failed.
+None of the configured backends support views.