Home | History | Annotate | Line # | Download | only in check
      1  1.12  christos /*	$NetBSD: named-checkconf.c,v 1.14 2026/01/29 18:36:26 christos Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5   1.1  christos  *
      6   1.8  christos  * SPDX-License-Identifier: MPL-2.0
      7   1.8  christos  *
      8   1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9   1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10   1.6  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11   1.1  christos  *
     12   1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13   1.1  christos  * information regarding copyright ownership.
     14   1.1  christos  */
     15   1.1  christos 
     16   1.1  christos /*! \file */
     17   1.1  christos 
     18   1.1  christos #include <errno.h>
     19   1.3  christos #include <stdbool.h>
     20   1.5  christos #include <stdio.h>
     21   1.1  christos #include <stdlib.h>
     22   1.1  christos 
     23  1.10  christos #include <isc/attributes.h>
     24   1.1  christos #include <isc/commandline.h>
     25   1.1  christos #include <isc/dir.h>
     26   1.1  christos #include <isc/hash.h>
     27   1.1  christos #include <isc/log.h>
     28   1.1  christos #include <isc/mem.h>
     29   1.1  christos #include <isc/result.h>
     30   1.1  christos #include <isc/string.h>
     31   1.1  christos #include <isc/util.h>
     32   1.1  christos 
     33   1.1  christos #include <dns/db.h>
     34   1.1  christos #include <dns/fixedname.h>
     35   1.1  christos #include <dns/log.h>
     36   1.1  christos #include <dns/name.h>
     37   1.1  christos #include <dns/rdataclass.h>
     38   1.1  christos #include <dns/rootns.h>
     39   1.1  christos #include <dns/zone.h>
     40   1.1  christos 
     41  1.12  christos #include <isccfg/check.h>
     42   1.5  christos #include <isccfg/grammar.h>
     43   1.5  christos #include <isccfg/namedconf.h>
     44   1.5  christos 
     45   1.1  christos #include "check-tool.h"
     46   1.1  christos 
     47   1.1  christos static const char *program = "named-checkconf";
     48   1.1  christos 
     49   1.1  christos isc_log_t *logc = NULL;
     50   1.1  christos 
     51   1.1  christos /*% usage */
     52  1.10  christos noreturn static void
     53  1.10  christos usage(void);
     54   1.1  christos 
     55   1.1  christos static void
     56   1.1  christos usage(void) {
     57   1.5  christos 	fprintf(stderr,
     58  1.14  christos 		"usage: %s [-achijklvz] [-p [-x]] [-t directory] "
     59   1.5  christos 		"[named.conf]\n",
     60   1.5  christos 		program);
     61  1.11  christos 	exit(EXIT_SUCCESS);
     62   1.1  christos }
     63   1.1  christos 
     64   1.1  christos /*% directory callback */
     65   1.1  christos static isc_result_t
     66   1.1  christos directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
     67   1.1  christos 	isc_result_t result;
     68   1.1  christos 	const char *directory;
     69   1.1  christos 
     70   1.1  christos 	REQUIRE(strcasecmp("directory", clausename) == 0);
     71   1.1  christos 
     72   1.1  christos 	UNUSED(arg);
     73   1.1  christos 	UNUSED(clausename);
     74   1.1  christos 
     75   1.1  christos 	/*
     76   1.1  christos 	 * Change directory.
     77   1.1  christos 	 */
     78   1.1  christos 	directory = cfg_obj_asstring(obj);
     79   1.1  christos 	result = isc_dir_chdir(directory);
     80   1.1  christos 	if (result != ISC_R_SUCCESS) {
     81   1.1  christos 		cfg_obj_log(obj, logc, ISC_LOG_ERROR,
     82   1.5  christos 			    "change directory to '%s' failed: %s\n", directory,
     83   1.5  christos 			    isc_result_totext(result));
     84  1.12  christos 		return result;
     85   1.1  christos 	}
     86   1.1  christos 
     87  1.12  christos 	return ISC_R_SUCCESS;
     88   1.1  christos }
     89   1.1  christos 
     90   1.3  christos static bool
     91   1.1  christos get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
     92   1.1  christos 	int i;
     93   1.1  christos 	for (i = 0;; i++) {
     94   1.5  christos 		if (maps[i] == NULL) {
     95  1.12  christos 			return false;
     96   1.5  christos 		}
     97   1.5  christos 		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
     98  1.12  christos 			return true;
     99   1.5  christos 		}
    100   1.1  christos 	}
    101   1.1  christos }
    102   1.1  christos 
    103   1.3  christos static bool
    104   1.1  christos get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
    105   1.1  christos 	const cfg_listelt_t *element;
    106   1.1  christos 	const cfg_obj_t *checknames;
    107   1.1  christos 	const cfg_obj_t *type;
    108   1.1  christos 	const cfg_obj_t *value;
    109   1.1  christos 	isc_result_t result;
    110   1.1  christos 	int i;
    111   1.1  christos 
    112   1.1  christos 	for (i = 0;; i++) {
    113   1.5  christos 		if (maps[i] == NULL) {
    114  1.12  christos 			return false;
    115   1.5  christos 		}
    116   1.1  christos 		checknames = NULL;
    117   1.1  christos 		result = cfg_map_get(maps[i], "check-names", &checknames);
    118   1.5  christos 		if (result != ISC_R_SUCCESS) {
    119   1.1  christos 			continue;
    120   1.5  christos 		}
    121   1.1  christos 		if (checknames != NULL && !cfg_obj_islist(checknames)) {
    122   1.1  christos 			*obj = checknames;
    123  1.12  christos 			return true;
    124   1.1  christos 		}
    125   1.5  christos 		for (element = cfg_list_first(checknames); element != NULL;
    126   1.5  christos 		     element = cfg_list_next(element))
    127   1.5  christos 		{
    128   1.1  christos 			value = cfg_listelt_value(element);
    129   1.1  christos 			type = cfg_tuple_get(value, "type");
    130   1.5  christos 			if ((strcasecmp(cfg_obj_asstring(type), "primary") !=
    131   1.5  christos 			     0) &&
    132   1.5  christos 			    (strcasecmp(cfg_obj_asstring(type), "master") != 0))
    133   1.3  christos 			{
    134   1.1  christos 				continue;
    135   1.3  christos 			}
    136   1.1  christos 			*obj = cfg_tuple_get(value, "mode");
    137  1.12  christos 			return true;
    138   1.1  christos 		}
    139   1.1  christos 	}
    140   1.1  christos }
    141   1.1  christos 
    142   1.1  christos static isc_result_t
    143   1.1  christos configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
    144   1.1  christos 	isc_result_t result;
    145   1.1  christos 	dns_db_t *db = NULL;
    146   1.1  christos 	dns_rdataclass_t rdclass;
    147   1.1  christos 	isc_textregion_t r;
    148   1.1  christos 
    149   1.5  christos 	if (zfile == NULL) {
    150  1.12  christos 		return ISC_R_FAILURE;
    151   1.5  christos 	}
    152   1.1  christos 
    153  1.12  christos 	r.base = UNCONST(zclass);
    154   1.1  christos 	r.length = strlen(zclass);
    155   1.1  christos 	result = dns_rdataclass_fromtext(&rdclass, &r);
    156   1.5  christos 	if (result != ISC_R_SUCCESS) {
    157  1.12  christos 		return result;
    158   1.5  christos 	}
    159   1.1  christos 
    160   1.1  christos 	result = dns_rootns_create(mctx, rdclass, zfile, &db);
    161   1.5  christos 	if (result != ISC_R_SUCCESS) {
    162  1.12  christos 		return result;
    163   1.5  christos 	}
    164   1.1  christos 
    165   1.1  christos 	dns_db_detach(&db);
    166  1.12  christos 	return ISC_R_SUCCESS;
    167   1.1  christos }
    168   1.1  christos 
    169   1.1  christos /*% configure the zone */
    170   1.1  christos static isc_result_t
    171   1.5  christos configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig,
    172   1.5  christos 	       const cfg_obj_t *vconfig, const cfg_obj_t *config,
    173   1.5  christos 	       isc_mem_t *mctx, bool list) {
    174   1.1  christos 	int i = 0;
    175   1.1  christos 	isc_result_t result;
    176   1.1  christos 	const char *zclass;
    177   1.1  christos 	const char *zname;
    178   1.1  christos 	const char *zfile = NULL;
    179   1.1  christos 	const cfg_obj_t *maps[4];
    180   1.6  christos 	const cfg_obj_t *primariesobj = NULL;
    181   1.1  christos 	const cfg_obj_t *inviewobj = NULL;
    182   1.1  christos 	const cfg_obj_t *zoptions = NULL;
    183   1.1  christos 	const cfg_obj_t *classobj = NULL;
    184   1.1  christos 	const cfg_obj_t *typeobj = NULL;
    185   1.1  christos 	const cfg_obj_t *fileobj = NULL;
    186   1.1  christos 	const cfg_obj_t *dlzobj = NULL;
    187   1.1  christos 	const cfg_obj_t *dbobj = NULL;
    188   1.1  christos 	const cfg_obj_t *obj = NULL;
    189   1.1  christos 	const cfg_obj_t *fmtobj = NULL;
    190   1.1  christos 	dns_masterformat_t masterformat;
    191   1.1  christos 	dns_ttl_t maxttl = 0;
    192   1.1  christos 
    193   1.1  christos 	zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
    194   1.1  christos 
    195   1.1  christos 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
    196   1.1  christos 	classobj = cfg_tuple_get(zconfig, "class");
    197   1.5  christos 	if (!cfg_obj_isstring(classobj)) {
    198   1.1  christos 		zclass = vclass;
    199   1.5  christos 	} else {
    200   1.1  christos 		zclass = cfg_obj_asstring(classobj);
    201   1.5  christos 	}
    202   1.1  christos 
    203   1.1  christos 	zoptions = cfg_tuple_get(zconfig, "options");
    204   1.1  christos 	maps[i++] = zoptions;
    205   1.5  christos 	if (vconfig != NULL) {
    206   1.1  christos 		maps[i++] = cfg_tuple_get(vconfig, "options");
    207   1.5  christos 	}
    208   1.1  christos 	if (config != NULL) {
    209   1.1  christos 		cfg_map_get(config, "options", &obj);
    210   1.5  christos 		if (obj != NULL) {
    211   1.1  christos 			maps[i++] = obj;
    212   1.5  christos 		}
    213   1.1  christos 	}
    214   1.1  christos 	maps[i] = NULL;
    215   1.1  christos 
    216   1.1  christos 	cfg_map_get(zoptions, "in-view", &inviewobj);
    217   1.1  christos 	if (inviewobj != NULL && list) {
    218   1.1  christos 		const char *inview = cfg_obj_asstring(inviewobj);
    219   1.1  christos 		printf("%s %s %s in-view %s\n", zname, zclass, view, inview);
    220   1.1  christos 	}
    221   1.5  christos 	if (inviewobj != NULL) {
    222  1.12  christos 		return ISC_R_SUCCESS;
    223   1.5  christos 	}
    224   1.1  christos 
    225   1.1  christos 	cfg_map_get(zoptions, "type", &typeobj);
    226   1.5  christos 	if (typeobj == NULL) {
    227  1.12  christos 		return ISC_R_FAILURE;
    228   1.5  christos 	}
    229   1.1  christos 
    230   1.1  christos 	if (list) {
    231   1.1  christos 		const char *ztype = cfg_obj_asstring(typeobj);
    232   1.1  christos 		printf("%s %s %s %s\n", zname, zclass, view, ztype);
    233  1.12  christos 		return ISC_R_SUCCESS;
    234   1.1  christos 	}
    235   1.1  christos 
    236   1.1  christos 	/*
    237   1.1  christos 	 * Skip checks when using an alternate data source.
    238   1.1  christos 	 */
    239   1.1  christos 	cfg_map_get(zoptions, "database", &dbobj);
    240  1.12  christos 	if (dbobj != NULL &&
    241  1.12  christos 	    strcmp(ZONEDB_DEFAULT, cfg_obj_asstring(dbobj)) != 0)
    242   1.5  christos 	{
    243  1.12  christos 		return ISC_R_SUCCESS;
    244   1.5  christos 	}
    245   1.1  christos 
    246   1.1  christos 	cfg_map_get(zoptions, "dlz", &dlzobj);
    247   1.5  christos 	if (dlzobj != NULL) {
    248  1.12  christos 		return ISC_R_SUCCESS;
    249   1.5  christos 	}
    250   1.1  christos 
    251   1.1  christos 	cfg_map_get(zoptions, "file", &fileobj);
    252   1.5  christos 	if (fileobj != NULL) {
    253   1.1  christos 		zfile = cfg_obj_asstring(fileobj);
    254   1.5  christos 	}
    255   1.1  christos 
    256   1.1  christos 	/*
    257   1.1  christos 	 * Check hints files for hint zones.
    258   1.1  christos 	 * Skip loading checks for any type other than
    259   1.1  christos 	 * master and redirect
    260   1.1  christos 	 */
    261   1.3  christos 	if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) {
    262  1.12  christos 		return configure_hint(zfile, zclass, mctx);
    263   1.3  christos 	} else if ((strcasecmp(cfg_obj_asstring(typeobj), "primary") != 0) &&
    264   1.3  christos 		   (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
    265   1.3  christos 		   (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
    266   1.3  christos 	{
    267  1.12  christos 		return ISC_R_SUCCESS;
    268   1.3  christos 	}
    269   1.1  christos 
    270   1.1  christos 	/*
    271  1.10  christos 	 * Is the redirect zone configured as a secondary?
    272   1.1  christos 	 */
    273   1.1  christos 	if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
    274   1.6  christos 		cfg_map_get(zoptions, "primaries", &primariesobj);
    275   1.6  christos 		if (primariesobj == NULL) {
    276   1.6  christos 			cfg_map_get(zoptions, "masters", &primariesobj);
    277   1.6  christos 		}
    278   1.6  christos 
    279   1.6  christos 		if (primariesobj != NULL) {
    280  1.12  christos 			return ISC_R_SUCCESS;
    281   1.5  christos 		}
    282   1.1  christos 	}
    283   1.1  christos 
    284   1.5  christos 	if (zfile == NULL) {
    285  1.12  christos 		return ISC_R_FAILURE;
    286   1.5  christos 	}
    287   1.1  christos 
    288   1.1  christos 	obj = NULL;
    289   1.1  christos 	if (get_maps(maps, "check-dup-records", &obj)) {
    290   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    291   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    292   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    293   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    294   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    295   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
    296   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    297   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
    298   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    299   1.3  christos 		} else {
    300   1.8  christos 			UNREACHABLE();
    301   1.3  christos 		}
    302   1.1  christos 	} else {
    303   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    304   1.1  christos 		zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    305   1.1  christos 	}
    306   1.1  christos 
    307   1.1  christos 	obj = NULL;
    308   1.1  christos 	if (get_maps(maps, "check-mx", &obj)) {
    309   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    310   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMX;
    311   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    312   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    313   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMX;
    314   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
    315   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    316   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMX;
    317   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    318   1.3  christos 		} else {
    319   1.8  christos 			UNREACHABLE();
    320   1.3  christos 		}
    321   1.1  christos 	} else {
    322   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKMX;
    323   1.1  christos 		zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    324   1.1  christos 	}
    325   1.1  christos 
    326   1.1  christos 	obj = NULL;
    327   1.1  christos 	if (get_maps(maps, "check-integrity", &obj)) {
    328   1.5  christos 		if (cfg_obj_asboolean(obj)) {
    329   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    330   1.5  christos 		} else {
    331   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
    332   1.5  christos 		}
    333   1.5  christos 	} else {
    334   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    335   1.5  christos 	}
    336   1.1  christos 
    337   1.1  christos 	obj = NULL;
    338   1.1  christos 	if (get_maps(maps, "check-mx-cname", &obj)) {
    339   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    340   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    341   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    342   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    343   1.1  christos 			zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
    344   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    345   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    346   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    347   1.1  christos 			zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
    348   1.3  christos 		} else {
    349   1.8  christos 			UNREACHABLE();
    350   1.3  christos 		}
    351   1.1  christos 	} else {
    352   1.1  christos 		zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    353   1.1  christos 		zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    354   1.1  christos 	}
    355   1.1  christos 
    356   1.1  christos 	obj = NULL;
    357   1.1  christos 	if (get_maps(maps, "check-srv-cname", &obj)) {
    358   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    359   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    360   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    361   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    362   1.1  christos 			zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
    363   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    364   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    365   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    366   1.1  christos 			zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
    367   1.3  christos 		} else {
    368   1.8  christos 			UNREACHABLE();
    369   1.3  christos 		}
    370   1.1  christos 	} else {
    371   1.1  christos 		zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    372   1.1  christos 		zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    373   1.1  christos 	}
    374   1.1  christos 
    375   1.1  christos 	obj = NULL;
    376   1.1  christos 	if (get_maps(maps, "check-sibling", &obj)) {
    377   1.5  christos 		if (cfg_obj_asboolean(obj)) {
    378   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKSIBLING;
    379   1.5  christos 		} else {
    380   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
    381   1.5  christos 		}
    382   1.1  christos 	}
    383   1.1  christos 
    384   1.1  christos 	obj = NULL;
    385   1.1  christos 	if (get_maps(maps, "check-spf", &obj)) {
    386   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    387   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKSPF;
    388   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    389   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKSPF;
    390   1.3  christos 		} else {
    391   1.8  christos 			UNREACHABLE();
    392   1.3  christos 		}
    393   1.1  christos 	} else {
    394   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKSPF;
    395   1.1  christos 	}
    396   1.1  christos 
    397   1.1  christos 	obj = NULL;
    398  1.12  christos 	if (get_maps(maps, "check-svcb", &obj)) {
    399  1.12  christos 		if (cfg_obj_asboolean(obj)) {
    400  1.12  christos 			zone_options |= DNS_ZONEOPT_CHECKSVCB;
    401  1.12  christos 		} else {
    402  1.12  christos 			zone_options &= ~DNS_ZONEOPT_CHECKSVCB;
    403  1.12  christos 		}
    404  1.12  christos 	} else {
    405  1.12  christos 		zone_options |= DNS_ZONEOPT_CHECKSVCB;
    406  1.12  christos 	}
    407  1.12  christos 
    408  1.12  christos 	obj = NULL;
    409   1.9  christos 	if (get_maps(maps, "check-wildcard", &obj)) {
    410   1.9  christos 		if (cfg_obj_asboolean(obj)) {
    411   1.9  christos 			zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
    412   1.9  christos 		} else {
    413   1.9  christos 			zone_options &= ~DNS_ZONEOPT_CHECKWILDCARD;
    414   1.9  christos 		}
    415   1.9  christos 	} else {
    416   1.9  christos 		zone_options |= DNS_ZONEOPT_CHECKWILDCARD;
    417   1.9  christos 	}
    418   1.9  christos 
    419   1.9  christos 	obj = NULL;
    420   1.1  christos 	if (get_checknames(maps, &obj)) {
    421   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    422   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKNAMES;
    423   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
    424   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    425   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKNAMES;
    426   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
    427   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    428   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
    429   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
    430   1.3  christos 		} else {
    431   1.8  christos 			UNREACHABLE();
    432   1.3  christos 		}
    433   1.1  christos 	} else {
    434   1.5  christos 		zone_options |= DNS_ZONEOPT_CHECKNAMES;
    435   1.5  christos 		zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
    436   1.1  christos 	}
    437   1.1  christos 
    438   1.1  christos 	masterformat = dns_masterformat_text;
    439   1.1  christos 	fmtobj = NULL;
    440   1.1  christos 	if (get_maps(maps, "masterfile-format", &fmtobj)) {
    441   1.1  christos 		const char *masterformatstr = cfg_obj_asstring(fmtobj);
    442   1.3  christos 		if (strcasecmp(masterformatstr, "text") == 0) {
    443   1.1  christos 			masterformat = dns_masterformat_text;
    444   1.3  christos 		} else if (strcasecmp(masterformatstr, "raw") == 0) {
    445   1.1  christos 			masterformat = dns_masterformat_raw;
    446   1.3  christos 		} else {
    447   1.8  christos 			UNREACHABLE();
    448   1.3  christos 		}
    449   1.1  christos 	}
    450   1.1  christos 
    451   1.1  christos 	obj = NULL;
    452   1.1  christos 	if (get_maps(maps, "max-zone-ttl", &obj)) {
    453   1.5  christos 		maxttl = cfg_obj_asduration(obj);
    454   1.3  christos 		zone_options |= DNS_ZONEOPT_CHECKTTL;
    455   1.1  christos 	}
    456   1.1  christos 
    457   1.5  christos 	result = load_zone(mctx, zname, zfile, masterformat, zclass, maxttl,
    458   1.5  christos 			   NULL);
    459   1.5  christos 	if (result != ISC_R_SUCCESS) {
    460   1.1  christos 		fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
    461  1.10  christos 			isc_result_totext(result));
    462   1.5  christos 	}
    463  1.12  christos 	return result;
    464   1.1  christos }
    465   1.1  christos 
    466   1.1  christos /*% configure a view */
    467   1.1  christos static isc_result_t
    468   1.1  christos configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
    469   1.5  christos 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, bool list) {
    470   1.1  christos 	const cfg_listelt_t *element;
    471   1.1  christos 	const cfg_obj_t *voptions;
    472   1.1  christos 	const cfg_obj_t *zonelist;
    473   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
    474   1.1  christos 	isc_result_t tresult;
    475   1.1  christos 
    476   1.1  christos 	voptions = NULL;
    477   1.5  christos 	if (vconfig != NULL) {
    478   1.1  christos 		voptions = cfg_tuple_get(vconfig, "options");
    479   1.5  christos 	}
    480   1.1  christos 
    481   1.1  christos 	zonelist = NULL;
    482   1.5  christos 	if (voptions != NULL) {
    483   1.1  christos 		(void)cfg_map_get(voptions, "zone", &zonelist);
    484   1.5  christos 	} else {
    485   1.1  christos 		(void)cfg_map_get(config, "zone", &zonelist);
    486   1.5  christos 	}
    487   1.1  christos 
    488   1.5  christos 	for (element = cfg_list_first(zonelist); element != NULL;
    489   1.1  christos 	     element = cfg_list_next(element))
    490   1.1  christos 	{
    491   1.1  christos 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
    492   1.5  christos 		tresult = configure_zone(vclass, view, zconfig, vconfig, config,
    493   1.5  christos 					 mctx, list);
    494   1.5  christos 		if (tresult != ISC_R_SUCCESS) {
    495   1.1  christos 			result = tresult;
    496   1.5  christos 		}
    497   1.1  christos 	}
    498  1.12  christos 	return result;
    499   1.1  christos }
    500   1.1  christos 
    501   1.1  christos static isc_result_t
    502   1.1  christos config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
    503   1.5  christos 		dns_rdataclass_t *classp) {
    504   1.1  christos 	isc_textregion_t r;
    505   1.1  christos 
    506   1.1  christos 	if (!cfg_obj_isstring(classobj)) {
    507   1.1  christos 		*classp = defclass;
    508  1.12  christos 		return ISC_R_SUCCESS;
    509   1.1  christos 	}
    510  1.12  christos 	r.base = UNCONST(cfg_obj_asstring(classobj));
    511   1.1  christos 	r.length = strlen(r.base);
    512  1.12  christos 	return dns_rdataclass_fromtext(classp, &r);
    513   1.1  christos }
    514   1.1  christos 
    515   1.1  christos /*% load zones from the configuration */
    516   1.1  christos static isc_result_t
    517   1.1  christos load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
    518   1.5  christos 		      bool list_zones) {
    519   1.1  christos 	const cfg_listelt_t *element;
    520   1.1  christos 	const cfg_obj_t *views;
    521   1.1  christos 	const cfg_obj_t *vconfig;
    522   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
    523   1.1  christos 	isc_result_t tresult;
    524   1.1  christos 
    525   1.1  christos 	views = NULL;
    526   1.1  christos 
    527   1.1  christos 	(void)cfg_map_get(config, "view", &views);
    528   1.5  christos 	for (element = cfg_list_first(views); element != NULL;
    529   1.1  christos 	     element = cfg_list_next(element))
    530   1.1  christos 	{
    531   1.1  christos 		const cfg_obj_t *classobj;
    532   1.1  christos 		dns_rdataclass_t viewclass;
    533   1.1  christos 		const char *vname;
    534   1.1  christos 		char buf[sizeof("CLASS65535")];
    535   1.1  christos 
    536   1.1  christos 		vconfig = cfg_listelt_value(element);
    537   1.5  christos 		if (vconfig == NULL) {
    538   1.1  christos 			continue;
    539   1.5  christos 		}
    540   1.1  christos 
    541   1.1  christos 		classobj = cfg_tuple_get(vconfig, "class");
    542   1.5  christos 		tresult = config_getclass(classobj, dns_rdataclass_in,
    543   1.5  christos 					  &viewclass);
    544   1.5  christos 		if (tresult != ISC_R_SUCCESS) {
    545   1.5  christos 			CHECK(tresult);
    546   1.5  christos 		}
    547   1.5  christos 
    548   1.5  christos 		if (dns_rdataclass_ismeta(viewclass)) {
    549   1.1  christos 			CHECK(ISC_R_FAILURE);
    550   1.5  christos 		}
    551   1.1  christos 
    552   1.1  christos 		dns_rdataclass_format(viewclass, buf, sizeof(buf));
    553   1.1  christos 		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
    554   1.1  christos 		tresult = configure_view(buf, vname, config, vconfig, mctx,
    555   1.1  christos 					 list_zones);
    556   1.5  christos 		if (tresult != ISC_R_SUCCESS) {
    557   1.1  christos 			result = tresult;
    558   1.5  christos 		}
    559   1.1  christos 	}
    560   1.1  christos 
    561   1.1  christos 	if (views == NULL) {
    562   1.1  christos 		tresult = configure_view("IN", "_default", config, NULL, mctx,
    563   1.1  christos 					 list_zones);
    564   1.5  christos 		if (tresult != ISC_R_SUCCESS) {
    565   1.1  christos 			result = tresult;
    566   1.5  christos 		}
    567   1.1  christos 	}
    568   1.1  christos 
    569   1.1  christos cleanup:
    570  1.12  christos 	return result;
    571   1.1  christos }
    572   1.1  christos 
    573   1.1  christos static void
    574   1.1  christos output(void *closure, const char *text, int textlen) {
    575   1.1  christos 	if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
    576  1.12  christos 		isc_result_t *result = closure;
    577   1.1  christos 		perror("fwrite");
    578  1.12  christos 		*result = ISC_R_FAILURE;
    579   1.1  christos 	}
    580   1.1  christos }
    581   1.1  christos 
    582   1.1  christos /*% The main processing routine */
    583   1.1  christos int
    584   1.1  christos main(int argc, char **argv) {
    585   1.1  christos 	int c;
    586   1.1  christos 	cfg_parser_t *parser = NULL;
    587   1.1  christos 	cfg_obj_t *config = NULL;
    588   1.1  christos 	const char *conffile = NULL;
    589   1.1  christos 	isc_mem_t *mctx = NULL;
    590  1.12  christos 	isc_result_t result = ISC_R_SUCCESS;
    591  1.12  christos 	bool cleanup_dst = false;
    592   1.3  christos 	bool load_zones = false;
    593   1.3  christos 	bool list_zones = false;
    594   1.3  christos 	bool print = false;
    595   1.5  christos 	bool nodeprecate = false;
    596   1.1  christos 	unsigned int flags = 0;
    597  1.12  christos 	unsigned int checkflags = BIND_CHECK_PLUGINS | BIND_CHECK_ALGORITHMS;
    598   1.1  christos 
    599   1.3  christos 	isc_commandline_errprint = false;
    600   1.1  christos 
    601   1.1  christos 	/*
    602   1.1  christos 	 * Process memory debugging argument first.
    603   1.1  christos 	 */
    604  1.14  christos #define CMDLINE_FLAGS "acdhijklm:t:pvxz"
    605   1.1  christos 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
    606   1.1  christos 		switch (c) {
    607   1.1  christos 		case 'm':
    608   1.1  christos 			if (strcasecmp(isc_commandline_argument, "record") == 0)
    609   1.5  christos 			{
    610   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
    611   1.5  christos 			}
    612   1.1  christos 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
    613   1.5  christos 			{
    614   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
    615   1.5  christos 			}
    616   1.1  christos 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
    617   1.5  christos 			{
    618   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
    619   1.5  christos 			}
    620   1.1  christos 			break;
    621   1.1  christos 		default:
    622   1.1  christos 			break;
    623   1.1  christos 		}
    624   1.1  christos 	}
    625   1.3  christos 	isc_commandline_reset = true;
    626   1.1  christos 
    627   1.5  christos 	isc_mem_create(&mctx);
    628   1.1  christos 
    629   1.1  christos 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
    630   1.1  christos 		switch (c) {
    631  1.12  christos 		case 'a':
    632  1.12  christos 			checkflags &= ~BIND_CHECK_ALGORITHMS;
    633  1.12  christos 			break;
    634  1.12  christos 
    635   1.3  christos 		case 'c':
    636  1.12  christos 			checkflags &= ~BIND_CHECK_PLUGINS;
    637   1.3  christos 			break;
    638   1.3  christos 
    639   1.1  christos 		case 'd':
    640   1.1  christos 			debug++;
    641   1.1  christos 			break;
    642   1.1  christos 
    643   1.5  christos 		case 'i':
    644   1.5  christos 			nodeprecate = true;
    645   1.5  christos 			break;
    646   1.5  christos 
    647   1.1  christos 		case 'j':
    648   1.3  christos 			nomerge = false;
    649   1.1  christos 			break;
    650   1.1  christos 
    651  1.14  christos 		case 'k':
    652  1.14  christos 			checkflags |= BIND_CHECK_KEYS;
    653  1.14  christos 			break;
    654  1.14  christos 
    655   1.1  christos 		case 'l':
    656   1.3  christos 			list_zones = true;
    657   1.1  christos 			break;
    658   1.1  christos 
    659   1.1  christos 		case 'm':
    660   1.1  christos 			break;
    661   1.1  christos 
    662   1.1  christos 		case 't':
    663   1.1  christos 			result = isc_dir_chroot(isc_commandline_argument);
    664   1.1  christos 			if (result != ISC_R_SUCCESS) {
    665   1.1  christos 				fprintf(stderr, "isc_dir_chroot: %s\n",
    666   1.1  christos 					isc_result_totext(result));
    667  1.12  christos 				CHECK(result);
    668   1.1  christos 			}
    669   1.1  christos 			break;
    670   1.1  christos 
    671   1.1  christos 		case 'p':
    672   1.3  christos 			print = true;
    673   1.1  christos 			break;
    674   1.1  christos 
    675   1.1  christos 		case 'v':
    676  1.10  christos 			printf("%s\n", PACKAGE_VERSION);
    677  1.12  christos 			result = ISC_R_SUCCESS;
    678  1.12  christos 			goto cleanup;
    679   1.1  christos 
    680   1.1  christos 		case 'x':
    681   1.1  christos 			flags |= CFG_PRINTER_XKEY;
    682   1.1  christos 			break;
    683   1.1  christos 
    684   1.1  christos 		case 'z':
    685   1.3  christos 			load_zones = true;
    686   1.3  christos 			docheckmx = false;
    687   1.3  christos 			docheckns = false;
    688   1.3  christos 			dochecksrv = false;
    689   1.1  christos 			break;
    690   1.1  christos 
    691   1.1  christos 		case '?':
    692   1.5  christos 			if (isc_commandline_option != '?') {
    693   1.1  christos 				fprintf(stderr, "%s: invalid argument -%c\n",
    694   1.1  christos 					program, isc_commandline_option);
    695   1.5  christos 			}
    696   1.8  christos 			FALLTHROUGH;
    697   1.1  christos 		case 'h':
    698  1.12  christos 			isc_mem_detach(&mctx);
    699   1.1  christos 			usage();
    700   1.1  christos 
    701   1.1  christos 		default:
    702   1.5  christos 			fprintf(stderr, "%s: unhandled option -%c\n", program,
    703   1.5  christos 				isc_commandline_option);
    704  1.12  christos 			CHECK(ISC_R_FAILURE);
    705   1.1  christos 		}
    706   1.1  christos 	}
    707   1.1  christos 
    708   1.1  christos 	if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
    709   1.1  christos 		fprintf(stderr, "%s: -x cannot be used without -p\n", program);
    710  1.12  christos 		CHECK(ISC_R_FAILURE);
    711   1.1  christos 	}
    712   1.1  christos 	if (print && list_zones) {
    713   1.1  christos 		fprintf(stderr, "%s: -l cannot be used with -p\n", program);
    714  1.12  christos 		CHECK(ISC_R_FAILURE);
    715   1.1  christos 	}
    716   1.1  christos 
    717   1.5  christos 	if (isc_commandline_index + 1 < argc) {
    718  1.12  christos 		isc_mem_detach(&mctx);
    719   1.1  christos 		usage();
    720   1.5  christos 	}
    721   1.5  christos 	if (argv[isc_commandline_index] != NULL) {
    722   1.1  christos 		conffile = argv[isc_commandline_index];
    723   1.5  christos 	}
    724   1.5  christos 	if (conffile == NULL || conffile[0] == '\0') {
    725   1.1  christos 		conffile = NAMED_CONFFILE;
    726   1.5  christos 	}
    727   1.1  christos 
    728  1.12  christos 	CHECK(setup_logging(mctx, stdout, &logc));
    729  1.12  christos 
    730  1.12  christos 	CHECK(dst_lib_init(mctx, NULL));
    731  1.12  christos 	cleanup_dst = true;
    732   1.1  christos 
    733  1.12  christos 	CHECK(cfg_parser_create(mctx, logc, &parser));
    734   1.1  christos 
    735   1.5  christos 	if (nodeprecate) {
    736   1.5  christos 		cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
    737   1.5  christos 	}
    738   1.1  christos 	cfg_parser_setcallback(parser, directory_callback, NULL);
    739   1.1  christos 
    740  1.12  christos 	CHECK(cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config));
    741  1.12  christos 	CHECK(isccfg_check_namedconf(config, checkflags, logc, mctx));
    742  1.12  christos 	if (load_zones || list_zones) {
    743  1.12  christos 		CHECK(load_zones_fromconfig(config, mctx, list_zones));
    744   1.5  christos 	}
    745   1.1  christos 
    746  1.12  christos 	if (print) {
    747  1.12  christos 		cfg_printx(config, flags, output, &result);
    748   1.3  christos 	}
    749   1.1  christos 
    750  1.12  christos cleanup:
    751  1.12  christos 	if (config != NULL) {
    752  1.12  christos 		cfg_obj_destroy(parser, &config);
    753   1.1  christos 	}
    754   1.1  christos 
    755  1.12  christos 	if (parser != NULL) {
    756  1.12  christos 		cfg_parser_destroy(&parser);
    757   1.5  christos 	}
    758   1.1  christos 
    759  1.12  christos 	if (cleanup_dst) {
    760  1.12  christos 		dst_lib_destroy();
    761  1.12  christos 	}
    762   1.1  christos 
    763  1.13  christos 	/*
    764  1.13  christos 	 * Wait for memory reclamation in dns_qp to finish.
    765  1.13  christos 	 */
    766  1.13  christos 	rcu_barrier();
    767  1.13  christos 
    768  1.12  christos 	if (logc != NULL) {
    769  1.12  christos 		isc_log_destroy(&logc);
    770  1.12  christos 	}
    771   1.1  christos 
    772  1.12  christos 	if (mctx != NULL) {
    773  1.12  christos 		isc_mem_destroy(&mctx);
    774  1.12  christos 	}
    775   1.1  christos 
    776  1.12  christos 	return result == ISC_R_SUCCESS ? 0 : 1;
    777   1.1  christos }
    778