Home | History | Annotate | Line # | Download | only in check
named-checkconf.c revision 1.11
      1   1.9  christos /*	$NetBSD: named-checkconf.c,v 1.11 2024/09/22 00:13:55 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/print.h>
     30   1.1  christos #include <isc/result.h>
     31   1.1  christos #include <isc/string.h>
     32   1.1  christos #include <isc/util.h>
     33   1.1  christos 
     34   1.1  christos #include <dns/db.h>
     35   1.1  christos #include <dns/fixedname.h>
     36   1.1  christos #include <dns/log.h>
     37   1.1  christos #include <dns/name.h>
     38   1.1  christos #include <dns/rdataclass.h>
     39   1.1  christos #include <dns/rootns.h>
     40   1.1  christos #include <dns/zone.h>
     41   1.1  christos 
     42   1.5  christos #include <isccfg/grammar.h>
     43   1.5  christos #include <isccfg/namedconf.h>
     44   1.5  christos 
     45   1.5  christos #include <bind9/check.h>
     46   1.5  christos 
     47   1.1  christos #include "check-tool.h"
     48   1.1  christos 
     49   1.1  christos static const char *program = "named-checkconf";
     50   1.1  christos 
     51   1.3  christos static bool loadplugins = true;
     52   1.3  christos 
     53   1.1  christos isc_log_t *logc = NULL;
     54   1.1  christos 
     55   1.5  christos #define CHECK(r)                             \
     56   1.5  christos 	do {                                 \
     57   1.5  christos 		result = (r);                \
     58   1.1  christos 		if (result != ISC_R_SUCCESS) \
     59   1.5  christos 			goto cleanup;        \
     60   1.7    rillig 	} while (0)
     61   1.1  christos 
     62   1.1  christos /*% usage */
     63  1.10  christos noreturn static void
     64  1.10  christos usage(void);
     65   1.1  christos 
     66   1.1  christos static void
     67   1.1  christos usage(void) {
     68   1.5  christos 	fprintf(stderr,
     69   1.5  christos 		"usage: %s [-chijlvz] [-p [-x]] [-t directory] "
     70   1.5  christos 		"[named.conf]\n",
     71   1.5  christos 		program);
     72  1.11  christos 	exit(EXIT_SUCCESS);
     73   1.1  christos }
     74   1.1  christos 
     75   1.1  christos /*% directory callback */
     76   1.1  christos static isc_result_t
     77   1.1  christos directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
     78   1.1  christos 	isc_result_t result;
     79   1.1  christos 	const char *directory;
     80   1.1  christos 
     81   1.1  christos 	REQUIRE(strcasecmp("directory", clausename) == 0);
     82   1.1  christos 
     83   1.1  christos 	UNUSED(arg);
     84   1.1  christos 	UNUSED(clausename);
     85   1.1  christos 
     86   1.1  christos 	/*
     87   1.1  christos 	 * Change directory.
     88   1.1  christos 	 */
     89   1.1  christos 	directory = cfg_obj_asstring(obj);
     90   1.1  christos 	result = isc_dir_chdir(directory);
     91   1.1  christos 	if (result != ISC_R_SUCCESS) {
     92   1.1  christos 		cfg_obj_log(obj, logc, ISC_LOG_ERROR,
     93   1.5  christos 			    "change directory to '%s' failed: %s\n", directory,
     94   1.5  christos 			    isc_result_totext(result));
     95   1.1  christos 		return (result);
     96   1.1  christos 	}
     97   1.1  christos 
     98   1.1  christos 	return (ISC_R_SUCCESS);
     99   1.1  christos }
    100   1.1  christos 
    101   1.3  christos static bool
    102   1.1  christos get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
    103   1.1  christos 	int i;
    104   1.1  christos 	for (i = 0;; i++) {
    105   1.5  christos 		if (maps[i] == NULL) {
    106   1.3  christos 			return (false);
    107   1.5  christos 		}
    108   1.5  christos 		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
    109   1.3  christos 			return (true);
    110   1.5  christos 		}
    111   1.1  christos 	}
    112   1.1  christos }
    113   1.1  christos 
    114   1.3  christos static bool
    115   1.1  christos get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
    116   1.1  christos 	const cfg_listelt_t *element;
    117   1.1  christos 	const cfg_obj_t *checknames;
    118   1.1  christos 	const cfg_obj_t *type;
    119   1.1  christos 	const cfg_obj_t *value;
    120   1.1  christos 	isc_result_t result;
    121   1.1  christos 	int i;
    122   1.1  christos 
    123   1.1  christos 	for (i = 0;; i++) {
    124   1.5  christos 		if (maps[i] == NULL) {
    125   1.3  christos 			return (false);
    126   1.5  christos 		}
    127   1.1  christos 		checknames = NULL;
    128   1.1  christos 		result = cfg_map_get(maps[i], "check-names", &checknames);
    129   1.5  christos 		if (result != ISC_R_SUCCESS) {
    130   1.1  christos 			continue;
    131   1.5  christos 		}
    132   1.1  christos 		if (checknames != NULL && !cfg_obj_islist(checknames)) {
    133   1.1  christos 			*obj = checknames;
    134   1.3  christos 			return (true);
    135   1.1  christos 		}
    136   1.5  christos 		for (element = cfg_list_first(checknames); element != NULL;
    137   1.5  christos 		     element = cfg_list_next(element))
    138   1.5  christos 		{
    139   1.1  christos 			value = cfg_listelt_value(element);
    140   1.1  christos 			type = cfg_tuple_get(value, "type");
    141   1.5  christos 			if ((strcasecmp(cfg_obj_asstring(type), "primary") !=
    142   1.5  christos 			     0) &&
    143   1.5  christos 			    (strcasecmp(cfg_obj_asstring(type), "master") != 0))
    144   1.3  christos 			{
    145   1.1  christos 				continue;
    146   1.3  christos 			}
    147   1.1  christos 			*obj = cfg_tuple_get(value, "mode");
    148   1.3  christos 			return (true);
    149   1.1  christos 		}
    150   1.1  christos 	}
    151   1.1  christos }
    152   1.1  christos 
    153   1.1  christos static isc_result_t
    154   1.1  christos configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
    155   1.1  christos 	isc_result_t result;
    156   1.1  christos 	dns_db_t *db = NULL;
    157   1.1  christos 	dns_rdataclass_t rdclass;
    158   1.1  christos 	isc_textregion_t r;
    159   1.1  christos 
    160   1.5  christos 	if (zfile == NULL) {
    161   1.1  christos 		return (ISC_R_FAILURE);
    162   1.5  christos 	}
    163   1.1  christos 
    164   1.1  christos 	DE_CONST(zclass, r.base);
    165   1.1  christos 	r.length = strlen(zclass);
    166   1.1  christos 	result = dns_rdataclass_fromtext(&rdclass, &r);
    167   1.5  christos 	if (result != ISC_R_SUCCESS) {
    168   1.1  christos 		return (result);
    169   1.5  christos 	}
    170   1.1  christos 
    171   1.1  christos 	result = dns_rootns_create(mctx, rdclass, zfile, &db);
    172   1.5  christos 	if (result != ISC_R_SUCCESS) {
    173   1.1  christos 		return (result);
    174   1.5  christos 	}
    175   1.1  christos 
    176   1.1  christos 	dns_db_detach(&db);
    177   1.1  christos 	return (ISC_R_SUCCESS);
    178   1.1  christos }
    179   1.1  christos 
    180   1.1  christos /*% configure the zone */
    181   1.1  christos static isc_result_t
    182   1.5  christos configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig,
    183   1.5  christos 	       const cfg_obj_t *vconfig, const cfg_obj_t *config,
    184   1.5  christos 	       isc_mem_t *mctx, bool list) {
    185   1.1  christos 	int i = 0;
    186   1.1  christos 	isc_result_t result;
    187   1.1  christos 	const char *zclass;
    188   1.1  christos 	const char *zname;
    189   1.1  christos 	const char *zfile = NULL;
    190   1.1  christos 	const cfg_obj_t *maps[4];
    191   1.6  christos 	const cfg_obj_t *primariesobj = NULL;
    192   1.1  christos 	const cfg_obj_t *inviewobj = NULL;
    193   1.1  christos 	const cfg_obj_t *zoptions = NULL;
    194   1.1  christos 	const cfg_obj_t *classobj = NULL;
    195   1.1  christos 	const cfg_obj_t *typeobj = NULL;
    196   1.1  christos 	const cfg_obj_t *fileobj = NULL;
    197   1.1  christos 	const cfg_obj_t *dlzobj = NULL;
    198   1.1  christos 	const cfg_obj_t *dbobj = NULL;
    199   1.1  christos 	const cfg_obj_t *obj = NULL;
    200   1.1  christos 	const cfg_obj_t *fmtobj = NULL;
    201   1.1  christos 	dns_masterformat_t masterformat;
    202   1.1  christos 	dns_ttl_t maxttl = 0;
    203   1.1  christos 
    204   1.1  christos 	zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
    205   1.1  christos 
    206   1.1  christos 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
    207   1.1  christos 	classobj = cfg_tuple_get(zconfig, "class");
    208   1.5  christos 	if (!cfg_obj_isstring(classobj)) {
    209   1.1  christos 		zclass = vclass;
    210   1.5  christos 	} else {
    211   1.1  christos 		zclass = cfg_obj_asstring(classobj);
    212   1.5  christos 	}
    213   1.1  christos 
    214   1.1  christos 	zoptions = cfg_tuple_get(zconfig, "options");
    215   1.1  christos 	maps[i++] = zoptions;
    216   1.5  christos 	if (vconfig != NULL) {
    217   1.1  christos 		maps[i++] = cfg_tuple_get(vconfig, "options");
    218   1.5  christos 	}
    219   1.1  christos 	if (config != NULL) {
    220   1.1  christos 		cfg_map_get(config, "options", &obj);
    221   1.5  christos 		if (obj != NULL) {
    222   1.1  christos 			maps[i++] = obj;
    223   1.5  christos 		}
    224   1.1  christos 	}
    225   1.1  christos 	maps[i] = NULL;
    226   1.1  christos 
    227   1.1  christos 	cfg_map_get(zoptions, "in-view", &inviewobj);
    228   1.1  christos 	if (inviewobj != NULL && list) {
    229   1.1  christos 		const char *inview = cfg_obj_asstring(inviewobj);
    230   1.1  christos 		printf("%s %s %s in-view %s\n", zname, zclass, view, inview);
    231   1.1  christos 	}
    232   1.5  christos 	if (inviewobj != NULL) {
    233   1.1  christos 		return (ISC_R_SUCCESS);
    234   1.5  christos 	}
    235   1.1  christos 
    236   1.1  christos 	cfg_map_get(zoptions, "type", &typeobj);
    237   1.5  christos 	if (typeobj == NULL) {
    238   1.1  christos 		return (ISC_R_FAILURE);
    239   1.5  christos 	}
    240   1.1  christos 
    241   1.1  christos 	if (list) {
    242   1.1  christos 		const char *ztype = cfg_obj_asstring(typeobj);
    243   1.1  christos 		printf("%s %s %s %s\n", zname, zclass, view, ztype);
    244   1.1  christos 		return (ISC_R_SUCCESS);
    245   1.1  christos 	}
    246   1.1  christos 
    247   1.1  christos 	/*
    248   1.1  christos 	 * Skip checks when using an alternate data source.
    249   1.1  christos 	 */
    250   1.1  christos 	cfg_map_get(zoptions, "database", &dbobj);
    251   1.5  christos 	if (dbobj != NULL && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
    252   1.1  christos 	    strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0)
    253   1.5  christos 	{
    254   1.1  christos 		return (ISC_R_SUCCESS);
    255   1.5  christos 	}
    256   1.1  christos 
    257   1.1  christos 	cfg_map_get(zoptions, "dlz", &dlzobj);
    258   1.5  christos 	if (dlzobj != NULL) {
    259   1.1  christos 		return (ISC_R_SUCCESS);
    260   1.5  christos 	}
    261   1.1  christos 
    262   1.1  christos 	cfg_map_get(zoptions, "file", &fileobj);
    263   1.5  christos 	if (fileobj != NULL) {
    264   1.1  christos 		zfile = cfg_obj_asstring(fileobj);
    265   1.5  christos 	}
    266   1.1  christos 
    267   1.1  christos 	/*
    268   1.1  christos 	 * Check hints files for hint zones.
    269   1.1  christos 	 * Skip loading checks for any type other than
    270   1.1  christos 	 * master and redirect
    271   1.1  christos 	 */
    272   1.3  christos 	if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) {
    273   1.1  christos 		return (configure_hint(zfile, zclass, mctx));
    274   1.3  christos 	} else if ((strcasecmp(cfg_obj_asstring(typeobj), "primary") != 0) &&
    275   1.3  christos 		   (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
    276   1.3  christos 		   (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
    277   1.3  christos 	{
    278   1.1  christos 		return (ISC_R_SUCCESS);
    279   1.3  christos 	}
    280   1.1  christos 
    281   1.1  christos 	/*
    282  1.10  christos 	 * Is the redirect zone configured as a secondary?
    283   1.1  christos 	 */
    284   1.1  christos 	if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
    285   1.6  christos 		cfg_map_get(zoptions, "primaries", &primariesobj);
    286   1.6  christos 		if (primariesobj == NULL) {
    287   1.6  christos 			cfg_map_get(zoptions, "masters", &primariesobj);
    288   1.6  christos 		}
    289   1.6  christos 
    290   1.6  christos 		if (primariesobj != NULL) {
    291   1.1  christos 			return (ISC_R_SUCCESS);
    292   1.5  christos 		}
    293   1.1  christos 	}
    294   1.1  christos 
    295   1.5  christos 	if (zfile == NULL) {
    296   1.1  christos 		return (ISC_R_FAILURE);
    297   1.5  christos 	}
    298   1.1  christos 
    299   1.1  christos 	obj = NULL;
    300   1.1  christos 	if (get_maps(maps, "check-dup-records", &obj)) {
    301   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    302   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    303   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    304   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    305   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    306   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
    307   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    308   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
    309   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    310   1.3  christos 		} else {
    311   1.8  christos 			UNREACHABLE();
    312   1.3  christos 		}
    313   1.1  christos 	} else {
    314   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    315   1.1  christos 		zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    316   1.1  christos 	}
    317   1.1  christos 
    318   1.1  christos 	obj = NULL;
    319   1.1  christos 	if (get_maps(maps, "check-mx", &obj)) {
    320   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    321   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMX;
    322   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    323   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    324   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMX;
    325   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
    326   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    327   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMX;
    328   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    329   1.3  christos 		} else {
    330   1.8  christos 			UNREACHABLE();
    331   1.3  christos 		}
    332   1.1  christos 	} else {
    333   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKMX;
    334   1.1  christos 		zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    335   1.1  christos 	}
    336   1.1  christos 
    337   1.1  christos 	obj = NULL;
    338   1.1  christos 	if (get_maps(maps, "check-integrity", &obj)) {
    339   1.5  christos 		if (cfg_obj_asboolean(obj)) {
    340   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    341   1.5  christos 		} else {
    342   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
    343   1.5  christos 		}
    344   1.5  christos 	} else {
    345   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    346   1.5  christos 	}
    347   1.1  christos 
    348   1.1  christos 	obj = NULL;
    349   1.1  christos 	if (get_maps(maps, "check-mx-cname", &obj)) {
    350   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    351   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    352   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    353   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    354   1.1  christos 			zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
    355   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    356   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    357   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    358   1.1  christos 			zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
    359   1.3  christos 		} else {
    360   1.8  christos 			UNREACHABLE();
    361   1.3  christos 		}
    362   1.1  christos 	} else {
    363   1.1  christos 		zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    364   1.1  christos 		zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    365   1.1  christos 	}
    366   1.1  christos 
    367   1.1  christos 	obj = NULL;
    368   1.1  christos 	if (get_maps(maps, "check-srv-cname", &obj)) {
    369   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    370   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    371   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    372   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    373   1.1  christos 			zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
    374   1.1  christos 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    375   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    376   1.1  christos 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    377   1.1  christos 			zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
    378   1.3  christos 		} else {
    379   1.8  christos 			UNREACHABLE();
    380   1.3  christos 		}
    381   1.1  christos 	} else {
    382   1.1  christos 		zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    383   1.1  christos 		zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    384   1.1  christos 	}
    385   1.1  christos 
    386   1.1  christos 	obj = NULL;
    387   1.1  christos 	if (get_maps(maps, "check-sibling", &obj)) {
    388   1.5  christos 		if (cfg_obj_asboolean(obj)) {
    389   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKSIBLING;
    390   1.5  christos 		} else {
    391   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
    392   1.5  christos 		}
    393   1.1  christos 	}
    394   1.1  christos 
    395   1.1  christos 	obj = NULL;
    396   1.1  christos 	if (get_maps(maps, "check-spf", &obj)) {
    397   1.1  christos 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    398   1.1  christos 			zone_options |= DNS_ZONEOPT_CHECKSPF;
    399   1.1  christos 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    400   1.1  christos 			zone_options &= ~DNS_ZONEOPT_CHECKSPF;
    401   1.3  christos 		} else {
    402   1.8  christos 			UNREACHABLE();
    403   1.3  christos 		}
    404   1.1  christos 	} else {
    405   1.1  christos 		zone_options |= DNS_ZONEOPT_CHECKSPF;
    406   1.1  christos 	}
    407   1.1  christos 
    408   1.1  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.1  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.1  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.1  christos 		return (ISC_R_SUCCESS);
    509   1.1  christos 	}
    510   1.1  christos 	DE_CONST(cfg_obj_asstring(classobj), r.base);
    511   1.1  christos 	r.length = strlen(r.base);
    512   1.1  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.1  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 	UNUSED(closure);
    576   1.1  christos 	if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
    577   1.1  christos 		perror("fwrite");
    578  1.11  christos 		exit(EXIT_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.1  christos 	isc_result_t result;
    591   1.1  christos 	int exit_status = 0;
    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.1  christos 
    598   1.3  christos 	isc_commandline_errprint = false;
    599   1.1  christos 
    600   1.1  christos 	/*
    601   1.1  christos 	 * Process memory debugging argument first.
    602   1.1  christos 	 */
    603   1.5  christos #define CMDLINE_FLAGS "cdhijlm:t:pvxz"
    604   1.1  christos 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
    605   1.1  christos 		switch (c) {
    606   1.1  christos 		case 'm':
    607   1.1  christos 			if (strcasecmp(isc_commandline_argument, "record") == 0)
    608   1.5  christos 			{
    609   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
    610   1.5  christos 			}
    611   1.1  christos 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
    612   1.5  christos 			{
    613   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
    614   1.5  christos 			}
    615   1.1  christos 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
    616   1.5  christos 			{
    617   1.1  christos 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
    618   1.5  christos 			}
    619   1.1  christos 			break;
    620   1.1  christos 		default:
    621   1.1  christos 			break;
    622   1.1  christos 		}
    623   1.1  christos 	}
    624   1.3  christos 	isc_commandline_reset = true;
    625   1.1  christos 
    626   1.5  christos 	isc_mem_create(&mctx);
    627   1.1  christos 
    628   1.1  christos 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
    629   1.1  christos 		switch (c) {
    630   1.3  christos 		case 'c':
    631   1.3  christos 			loadplugins = false;
    632   1.3  christos 			break;
    633   1.3  christos 
    634   1.1  christos 		case 'd':
    635   1.1  christos 			debug++;
    636   1.1  christos 			break;
    637   1.1  christos 
    638   1.5  christos 		case 'i':
    639   1.5  christos 			nodeprecate = true;
    640   1.5  christos 			break;
    641   1.5  christos 
    642   1.1  christos 		case 'j':
    643   1.3  christos 			nomerge = false;
    644   1.1  christos 			break;
    645   1.1  christos 
    646   1.1  christos 		case 'l':
    647   1.3  christos 			list_zones = true;
    648   1.1  christos 			break;
    649   1.1  christos 
    650   1.1  christos 		case 'm':
    651   1.1  christos 			break;
    652   1.1  christos 
    653   1.1  christos 		case 't':
    654   1.1  christos 			result = isc_dir_chroot(isc_commandline_argument);
    655   1.1  christos 			if (result != ISC_R_SUCCESS) {
    656   1.1  christos 				fprintf(stderr, "isc_dir_chroot: %s\n",
    657   1.1  christos 					isc_result_totext(result));
    658  1.11  christos 				exit(EXIT_FAILURE);
    659   1.1  christos 			}
    660   1.1  christos 			break;
    661   1.1  christos 
    662   1.1  christos 		case 'p':
    663   1.3  christos 			print = true;
    664   1.1  christos 			break;
    665   1.1  christos 
    666   1.1  christos 		case 'v':
    667  1.10  christos 			printf("%s\n", PACKAGE_VERSION);
    668  1.11  christos 			exit(EXIT_SUCCESS);
    669   1.1  christos 
    670   1.1  christos 		case 'x':
    671   1.1  christos 			flags |= CFG_PRINTER_XKEY;
    672   1.1  christos 			break;
    673   1.1  christos 
    674   1.1  christos 		case 'z':
    675   1.3  christos 			load_zones = true;
    676   1.3  christos 			docheckmx = false;
    677   1.3  christos 			docheckns = false;
    678   1.3  christos 			dochecksrv = false;
    679   1.1  christos 			break;
    680   1.1  christos 
    681   1.1  christos 		case '?':
    682   1.5  christos 			if (isc_commandline_option != '?') {
    683   1.1  christos 				fprintf(stderr, "%s: invalid argument -%c\n",
    684   1.1  christos 					program, isc_commandline_option);
    685   1.5  christos 			}
    686   1.8  christos 			FALLTHROUGH;
    687   1.1  christos 		case 'h':
    688   1.1  christos 			usage();
    689   1.1  christos 
    690   1.1  christos 		default:
    691   1.5  christos 			fprintf(stderr, "%s: unhandled option -%c\n", program,
    692   1.5  christos 				isc_commandline_option);
    693  1.11  christos 			exit(EXIT_FAILURE);
    694   1.1  christos 		}
    695   1.1  christos 	}
    696   1.1  christos 
    697   1.1  christos 	if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
    698   1.1  christos 		fprintf(stderr, "%s: -x cannot be used without -p\n", program);
    699  1.11  christos 		exit(EXIT_FAILURE);
    700   1.1  christos 	}
    701   1.1  christos 	if (print && list_zones) {
    702   1.1  christos 		fprintf(stderr, "%s: -l cannot be used with -p\n", program);
    703  1.11  christos 		exit(EXIT_FAILURE);
    704   1.1  christos 	}
    705   1.1  christos 
    706   1.5  christos 	if (isc_commandline_index + 1 < argc) {
    707   1.1  christos 		usage();
    708   1.5  christos 	}
    709   1.5  christos 	if (argv[isc_commandline_index] != NULL) {
    710   1.1  christos 		conffile = argv[isc_commandline_index];
    711   1.5  christos 	}
    712   1.5  christos 	if (conffile == NULL || conffile[0] == '\0') {
    713   1.1  christos 		conffile = NAMED_CONFFILE;
    714   1.5  christos 	}
    715   1.1  christos 
    716   1.1  christos 	RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
    717   1.1  christos 
    718   1.1  christos 	RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
    719   1.1  christos 
    720   1.5  christos 	if (nodeprecate) {
    721   1.5  christos 		cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
    722   1.5  christos 	}
    723   1.1  christos 	cfg_parser_setcallback(parser, directory_callback, NULL);
    724   1.1  christos 
    725   1.1  christos 	if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
    726   1.1  christos 	    ISC_R_SUCCESS)
    727   1.5  christos 	{
    728  1.11  christos 		exit(EXIT_FAILURE);
    729   1.5  christos 	}
    730   1.1  christos 
    731  1.10  christos 	result = bind9_check_namedconf(config, loadplugins, nodeprecate, logc,
    732  1.10  christos 				       mctx);
    733   1.3  christos 	if (result != ISC_R_SUCCESS) {
    734   1.1  christos 		exit_status = 1;
    735   1.3  christos 	}
    736   1.1  christos 
    737   1.1  christos 	if (result == ISC_R_SUCCESS && (load_zones || list_zones)) {
    738   1.1  christos 		result = load_zones_fromconfig(config, mctx, list_zones);
    739   1.5  christos 		if (result != ISC_R_SUCCESS) {
    740   1.1  christos 			exit_status = 1;
    741   1.5  christos 		}
    742   1.1  christos 	}
    743   1.1  christos 
    744   1.5  christos 	if (print && exit_status == 0) {
    745   1.1  christos 		cfg_printx(config, flags, output, NULL);
    746   1.5  christos 	}
    747   1.1  christos 	cfg_obj_destroy(parser, &config);
    748   1.1  christos 
    749   1.1  christos 	cfg_parser_destroy(&parser);
    750   1.1  christos 
    751   1.1  christos 	isc_log_destroy(&logc);
    752   1.1  christos 
    753   1.1  christos 	isc_mem_destroy(&mctx);
    754   1.1  christos 
    755   1.1  christos 	return (exit_status);
    756   1.1  christos }
    757