00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027
00028 #include <isc/commandline.h>
00029 #include <isc/dir.h>
00030 #include <isc/entropy.h>
00031 #include <isc/hash.h>
00032 #include <isc/log.h>
00033 #include <isc/mem.h>
00034 #include <isc/result.h>
00035 #include <isc/string.h>
00036 #include <isc/util.h>
00037
00038 #include <isccfg/namedconf.h>
00039
00040 #include <bind9/check.h>
00041
00042 #include <dns/db.h>
00043 #include <dns/fixedname.h>
00044 #include <dns/log.h>
00045 #include <dns/name.h>
00046 #include <dns/rdataclass.h>
00047 #include <dns/result.h>
00048 #include <dns/rootns.h>
00049 #include <dns/zone.h>
00050
00051 #include "check-tool.h"
00052
00053 static const char *program = "named-checkconf";
00054
00055 isc_log_t *logc = NULL;
00056
00057 #define CHECK(r)\
00058 do { \
00059 result = (r); \
00060 if (result != ISC_R_SUCCESS) \
00061 goto cleanup; \
00062 } while (0)
00063
00064
00065 ISC_PLATFORM_NORETURN_PRE static void
00066 usage(void) ISC_PLATFORM_NORETURN_POST;
00067
00068 static void
00069 usage(void) {
00070 fprintf(stderr, "usage: %s [-h] [-j] [-p [-x]] [-v] [-z] [-t directory] "
00071 "[named.conf]\n", program);
00072 exit(1);
00073 }
00074
00075
00076 static isc_result_t
00077 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
00078 isc_result_t result;
00079 const char *directory;
00080
00081 REQUIRE(strcasecmp("directory", clausename) == 0);
00082
00083 UNUSED(arg);
00084 UNUSED(clausename);
00085
00086
00087
00088
00089 directory = cfg_obj_asstring(obj);
00090 result = isc_dir_chdir(directory);
00091 if (result != ISC_R_SUCCESS) {
00092 cfg_obj_log(obj, logc, ISC_LOG_ERROR,
00093 "change directory to '%s' failed: %s\n",
00094 directory, isc_result_totext(result));
00095 return (result);
00096 }
00097
00098 return (ISC_R_SUCCESS);
00099 }
00100
00101 static isc_boolean_t
00102 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
00103 int i;
00104 for (i = 0;; i++) {
00105 if (maps[i] == NULL)
00106 return (ISC_FALSE);
00107 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
00108 return (ISC_TRUE);
00109 }
00110 }
00111
00112 static isc_boolean_t
00113 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
00114 const cfg_listelt_t *element;
00115 const cfg_obj_t *checknames;
00116 const cfg_obj_t *type;
00117 const cfg_obj_t *value;
00118 isc_result_t result;
00119 int i;
00120
00121 for (i = 0;; i++) {
00122 if (maps[i] == NULL)
00123 return (ISC_FALSE);
00124 checknames = NULL;
00125 result = cfg_map_get(maps[i], "check-names", &checknames);
00126 if (result != ISC_R_SUCCESS)
00127 continue;
00128 if (checknames != NULL && !cfg_obj_islist(checknames)) {
00129 *obj = checknames;
00130 return (ISC_TRUE);
00131 }
00132 for (element = cfg_list_first(checknames);
00133 element != NULL;
00134 element = cfg_list_next(element)) {
00135 value = cfg_listelt_value(element);
00136 type = cfg_tuple_get(value, "type");
00137 if (strcasecmp(cfg_obj_asstring(type), "master") != 0)
00138 continue;
00139 *obj = cfg_tuple_get(value, "mode");
00140 return (ISC_TRUE);
00141 }
00142 }
00143 }
00144
00145 static isc_result_t
00146 configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
00147 isc_result_t result;
00148 dns_db_t *db = NULL;
00149 dns_rdataclass_t rdclass;
00150 isc_textregion_t r;
00151
00152 if (zfile == NULL)
00153 return (ISC_R_FAILURE);
00154
00155 DE_CONST(zclass, r.base);
00156 r.length = strlen(zclass);
00157 result = dns_rdataclass_fromtext(&rdclass, &r);
00158 if (result != ISC_R_SUCCESS)
00159 return (result);
00160
00161 result = dns_rootns_create(mctx, rdclass, zfile, &db);
00162 if (result != ISC_R_SUCCESS)
00163 return (result);
00164
00165 dns_db_detach(&db);
00166 return (ISC_R_SUCCESS);
00167 }
00168
00169
00170 static isc_result_t
00171 configure_zone(const char *vclass, const char *view,
00172 const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
00173 const cfg_obj_t *config, isc_mem_t *mctx)
00174 {
00175 int i = 0;
00176 isc_result_t result;
00177 const char *zclass;
00178 const char *zname;
00179 const char *zfile = NULL;
00180 const cfg_obj_t *maps[4];
00181 const cfg_obj_t *mastersobj = NULL;
00182 const cfg_obj_t *zoptions = NULL;
00183 const cfg_obj_t *classobj = NULL;
00184 const cfg_obj_t *typeobj = NULL;
00185 const cfg_obj_t *fileobj = NULL;
00186 const cfg_obj_t *dlzobj = NULL;
00187 const cfg_obj_t *dbobj = NULL;
00188 const cfg_obj_t *obj = NULL;
00189 const cfg_obj_t *fmtobj = NULL;
00190 dns_masterformat_t masterformat;
00191 dns_ttl_t maxttl = 0;
00192
00193 zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
00194
00195 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
00196 classobj = cfg_tuple_get(zconfig, "class");
00197 if (!cfg_obj_isstring(classobj))
00198 zclass = vclass;
00199 else
00200 zclass = cfg_obj_asstring(classobj);
00201
00202 zoptions = cfg_tuple_get(zconfig, "options");
00203 maps[i++] = zoptions;
00204 if (vconfig != NULL)
00205 maps[i++] = cfg_tuple_get(vconfig, "options");
00206 if (config != NULL) {
00207 cfg_map_get(config, "options", &obj);
00208 if (obj != NULL)
00209 maps[i++] = obj;
00210 }
00211 maps[i] = NULL;
00212
00213 cfg_map_get(zoptions, "type", &typeobj);
00214 if (typeobj == NULL)
00215 return (ISC_R_FAILURE);
00216
00217
00218
00219
00220 cfg_map_get(zoptions, "database", &dbobj);
00221 if (dbobj != NULL &&
00222 strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
00223 strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0)
00224 return (ISC_R_SUCCESS);
00225
00226 cfg_map_get(zoptions, "dlz", &dlzobj);
00227 if (dlzobj != NULL)
00228 return (ISC_R_SUCCESS);
00229
00230 cfg_map_get(zoptions, "file", &fileobj);
00231 if (fileobj != NULL)
00232 zfile = cfg_obj_asstring(fileobj);
00233
00234
00235
00236
00237
00238
00239 if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0)
00240 return (configure_hint(zfile, zclass, mctx));
00241 else if ((strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
00242 (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
00243 return (ISC_R_SUCCESS);
00244
00245
00246
00247
00248 if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
00249 cfg_map_get(zoptions, "masters", &mastersobj);
00250 if (mastersobj != NULL)
00251 return (ISC_R_SUCCESS);
00252 }
00253
00254 if (zfile == NULL)
00255 return (ISC_R_FAILURE);
00256
00257 obj = NULL;
00258 if (get_maps(maps, "check-dup-records", &obj)) {
00259 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00260 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
00261 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
00262 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
00263 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
00264 zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
00265 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00266 zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
00267 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
00268 } else
00269 INSIST(0);
00270 } else {
00271 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
00272 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
00273 }
00274
00275 obj = NULL;
00276 if (get_maps(maps, "check-mx", &obj)) {
00277 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00278 zone_options |= DNS_ZONEOPT_CHECKMX;
00279 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
00280 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
00281 zone_options |= DNS_ZONEOPT_CHECKMX;
00282 zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
00283 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00284 zone_options &= ~DNS_ZONEOPT_CHECKMX;
00285 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
00286 } else
00287 INSIST(0);
00288 } else {
00289 zone_options |= DNS_ZONEOPT_CHECKMX;
00290 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
00291 }
00292
00293 obj = NULL;
00294 if (get_maps(maps, "check-integrity", &obj)) {
00295 if (cfg_obj_asboolean(obj))
00296 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
00297 else
00298 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
00299 } else
00300 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
00301
00302 obj = NULL;
00303 if (get_maps(maps, "check-mx-cname", &obj)) {
00304 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00305 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
00306 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
00307 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
00308 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
00309 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
00310 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00311 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
00312 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
00313 } else
00314 INSIST(0);
00315 } else {
00316 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
00317 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
00318 }
00319
00320 obj = NULL;
00321 if (get_maps(maps, "check-srv-cname", &obj)) {
00322 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00323 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
00324 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
00325 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
00326 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
00327 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
00328 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00329 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
00330 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
00331 } else
00332 INSIST(0);
00333 } else {
00334 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
00335 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
00336 }
00337
00338 obj = NULL;
00339 if (get_maps(maps, "check-sibling", &obj)) {
00340 if (cfg_obj_asboolean(obj))
00341 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
00342 else
00343 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
00344 }
00345
00346 obj = NULL;
00347 if (get_maps(maps, "check-spf", &obj)) {
00348 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00349 zone_options |= DNS_ZONEOPT_CHECKSPF;
00350 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00351 zone_options &= ~DNS_ZONEOPT_CHECKSPF;
00352 } else
00353 INSIST(0);
00354 } else {
00355 zone_options |= DNS_ZONEOPT_CHECKSPF;
00356 }
00357
00358 obj = NULL;
00359 if (get_checknames(maps, &obj)) {
00360 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
00361 zone_options |= DNS_ZONEOPT_CHECKNAMES;
00362 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
00363 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
00364 zone_options |= DNS_ZONEOPT_CHECKNAMES;
00365 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
00366 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
00367 zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
00368 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
00369 } else
00370 INSIST(0);
00371 } else {
00372 zone_options |= DNS_ZONEOPT_CHECKNAMES;
00373 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
00374 }
00375
00376 masterformat = dns_masterformat_text;
00377 fmtobj = NULL;
00378 if (get_maps(maps, "masterfile-format", &fmtobj)) {
00379 const char *masterformatstr = cfg_obj_asstring(fmtobj);
00380 if (strcasecmp(masterformatstr, "text") == 0)
00381 masterformat = dns_masterformat_text;
00382 else if (strcasecmp(masterformatstr, "raw") == 0)
00383 masterformat = dns_masterformat_raw;
00384 else if (strcasecmp(masterformatstr, "map") == 0)
00385 masterformat = dns_masterformat_map;
00386 else
00387 INSIST(0);
00388 }
00389
00390 obj = NULL;
00391 if (get_maps(maps, "max-zone-ttl", &obj)) {
00392 maxttl = cfg_obj_asuint32(obj);
00393 zone_options2 |= DNS_ZONEOPT2_CHECKTTL;
00394 }
00395
00396 result = load_zone(mctx, zname, zfile, masterformat,
00397 zclass, maxttl, NULL);
00398 if (result != ISC_R_SUCCESS)
00399 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
00400 dns_result_totext(result));
00401 return (result);
00402 }
00403
00404
00405 static isc_result_t
00406 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
00407 const cfg_obj_t *vconfig, isc_mem_t *mctx)
00408 {
00409 const cfg_listelt_t *element;
00410 const cfg_obj_t *voptions;
00411 const cfg_obj_t *zonelist;
00412 isc_result_t result = ISC_R_SUCCESS;
00413 isc_result_t tresult;
00414
00415 voptions = NULL;
00416 if (vconfig != NULL)
00417 voptions = cfg_tuple_get(vconfig, "options");
00418
00419 zonelist = NULL;
00420 if (voptions != NULL)
00421 (void)cfg_map_get(voptions, "zone", &zonelist);
00422 else
00423 (void)cfg_map_get(config, "zone", &zonelist);
00424
00425 for (element = cfg_list_first(zonelist);
00426 element != NULL;
00427 element = cfg_list_next(element))
00428 {
00429 const cfg_obj_t *zconfig = cfg_listelt_value(element);
00430 tresult = configure_zone(vclass, view, zconfig, vconfig,
00431 config, mctx);
00432 if (tresult != ISC_R_SUCCESS)
00433 result = tresult;
00434 }
00435 return (result);
00436 }
00437
00438
00439
00440 static isc_result_t
00441 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
00442 const cfg_listelt_t *element;
00443 const cfg_obj_t *classobj;
00444 const cfg_obj_t *views;
00445 const cfg_obj_t *vconfig;
00446 const char *vclass;
00447 isc_result_t result = ISC_R_SUCCESS;
00448 isc_result_t tresult;
00449
00450 views = NULL;
00451
00452 (void)cfg_map_get(config, "view", &views);
00453 for (element = cfg_list_first(views);
00454 element != NULL;
00455 element = cfg_list_next(element))
00456 {
00457 const char *vname;
00458
00459 vclass = "IN";
00460 vconfig = cfg_listelt_value(element);
00461 if (vconfig != NULL) {
00462 classobj = cfg_tuple_get(vconfig, "class");
00463 if (cfg_obj_isstring(classobj))
00464 vclass = cfg_obj_asstring(classobj);
00465 }
00466 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
00467 tresult = configure_view(vclass, vname, config, vconfig, mctx);
00468 if (tresult != ISC_R_SUCCESS)
00469 result = tresult;
00470 }
00471
00472 if (views == NULL) {
00473 tresult = configure_view("IN", "_default", config, NULL, mctx);
00474 if (tresult != ISC_R_SUCCESS)
00475 result = tresult;
00476 }
00477 return (result);
00478 }
00479
00480 static void
00481 output(void *closure, const char *text, int textlen) {
00482 UNUSED(closure);
00483 if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
00484 perror("fwrite");
00485 exit(1);
00486 }
00487 }
00488
00489
00490 int
00491 main(int argc, char **argv) {
00492 int c;
00493 cfg_parser_t *parser = NULL;
00494 cfg_obj_t *config = NULL;
00495 const char *conffile = NULL;
00496 isc_mem_t *mctx = NULL;
00497 isc_result_t result;
00498 int exit_status = 0;
00499 isc_entropy_t *ectx = NULL;
00500 isc_boolean_t load_zones = ISC_FALSE;
00501 isc_boolean_t print = ISC_FALSE;
00502 unsigned int flags = 0;
00503
00504 isc_commandline_errprint = ISC_FALSE;
00505
00506
00507
00508
00509 #define CMDLINE_FLAGS "dhjm:t:pvxz"
00510 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
00511 switch (c) {
00512 case 'm':
00513 if (strcasecmp(isc_commandline_argument, "record") == 0)
00514 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
00515 if (strcasecmp(isc_commandline_argument, "trace") == 0)
00516 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
00517 if (strcasecmp(isc_commandline_argument, "usage") == 0)
00518 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
00519 if (strcasecmp(isc_commandline_argument, "size") == 0)
00520 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
00521 if (strcasecmp(isc_commandline_argument, "mctx") == 0)
00522 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
00523 break;
00524 default:
00525 break;
00526 }
00527 }
00528 isc_commandline_reset = ISC_TRUE;
00529
00530 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
00531
00532 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
00533 switch (c) {
00534 case 'd':
00535 debug++;
00536 break;
00537
00538 case 'j':
00539 nomerge = ISC_FALSE;
00540 break;
00541
00542 case 'm':
00543 break;
00544
00545 case 't':
00546 result = isc_dir_chroot(isc_commandline_argument);
00547 if (result != ISC_R_SUCCESS) {
00548 fprintf(stderr, "isc_dir_chroot: %s\n",
00549 isc_result_totext(result));
00550 exit(1);
00551 }
00552 break;
00553
00554 case 'p':
00555 print = ISC_TRUE;
00556 break;
00557
00558 case 'v':
00559 printf(VERSION "\n");
00560 exit(0);
00561
00562 case 'x':
00563 flags |= CFG_PRINTER_XKEY;
00564 break;
00565
00566 case 'z':
00567 load_zones = ISC_TRUE;
00568 docheckmx = ISC_FALSE;
00569 docheckns = ISC_FALSE;
00570 dochecksrv = ISC_FALSE;
00571 break;
00572
00573 case '?':
00574 if (isc_commandline_option != '?')
00575 fprintf(stderr, "%s: invalid argument -%c\n",
00576 program, isc_commandline_option);
00577
00578 case 'h':
00579 usage();
00580
00581 default:
00582 fprintf(stderr, "%s: unhandled option -%c\n",
00583 program, isc_commandline_option);
00584 exit(1);
00585 }
00586 }
00587
00588 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
00589 fprintf(stderr, "%s: -x cannot be used without -p\n", program);
00590 exit(1);
00591 }
00592
00593 if (isc_commandline_index + 1 < argc)
00594 usage();
00595 if (argv[isc_commandline_index] != NULL)
00596 conffile = argv[isc_commandline_index];
00597 if (conffile == NULL || conffile[0] == '\0')
00598 conffile = NAMED_CONFFILE;
00599
00600 #ifdef _WIN32
00601 InitSockets();
00602 #endif
00603
00604 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
00605
00606 RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
00607 RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
00608 == ISC_R_SUCCESS);
00609
00610 dns_result_register();
00611
00612 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
00613
00614 cfg_parser_setcallback(parser, directory_callback, NULL);
00615
00616 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
00617 ISC_R_SUCCESS)
00618 exit(1);
00619
00620 result = bind9_check_namedconf(config, logc, mctx);
00621 if (result != ISC_R_SUCCESS)
00622 exit_status = 1;
00623
00624 if (result == ISC_R_SUCCESS && load_zones) {
00625 result = load_zones_fromconfig(config, mctx);
00626 if (result != ISC_R_SUCCESS)
00627 exit_status = 1;
00628 }
00629
00630 if (print && exit_status == 0)
00631 cfg_printx(config, flags, output, NULL);
00632 cfg_obj_destroy(parser, &config);
00633
00634 cfg_parser_destroy(&parser);
00635
00636 dns_name_destroy();
00637
00638 isc_log_destroy(&logc);
00639
00640 isc_hash_destroy();
00641 isc_entropy_detach(&ectx);
00642
00643 isc_mem_destroy(&mctx);
00644
00645 #ifdef _WIN32
00646 DestroySockets();
00647 #endif
00648
00649 return (exit_status);
00650 }