1135446Strhodes/* 2254897Serwin * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2002 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id: check-tool.c,v 1.44 2011/12/22 07:32:39 each Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <stdio.h> 25135446Strhodes 26216175Sdougb#ifdef _WIN32 27216175Sdougb#include <Winsock2.h> 28216175Sdougb#endif 29216175Sdougb 30135446Strhodes#include "check-tool.h" 31135446Strhodes#include <isc/buffer.h> 32135446Strhodes#include <isc/log.h> 33193149Sdougb#include <isc/mem.h> 34193149Sdougb#include <isc/netdb.h> 35170222Sdougb#include <isc/net.h> 36135446Strhodes#include <isc/region.h> 37135446Strhodes#include <isc/stdio.h> 38174187Sdougb#include <isc/string.h> 39193149Sdougb#include <isc/symtab.h> 40135446Strhodes#include <isc/types.h> 41193149Sdougb#include <isc/util.h> 42135446Strhodes 43135446Strhodes#include <dns/fixedname.h> 44143731Sdougb#include <dns/log.h> 45135446Strhodes#include <dns/name.h> 46170222Sdougb#include <dns/rdata.h> 47135446Strhodes#include <dns/rdataclass.h> 48170222Sdougb#include <dns/rdataset.h> 49135446Strhodes#include <dns/types.h> 50135446Strhodes#include <dns/zone.h> 51135446Strhodes 52170222Sdougb#include <isccfg/log.h> 53170222Sdougb 54186462Sdougb#ifndef CHECK_SIBLING 55186462Sdougb#define CHECK_SIBLING 1 56186462Sdougb#endif 57186462Sdougb 58186462Sdougb#ifndef CHECK_LOCAL 59186462Sdougb#define CHECK_LOCAL 1 60186462Sdougb#endif 61186462Sdougb 62170222Sdougb#ifdef HAVE_ADDRINFO 63170222Sdougb#ifdef HAVE_GETADDRINFO 64170222Sdougb#ifdef HAVE_GAISTRERROR 65170222Sdougb#define USE_GETADDRINFO 66170222Sdougb#endif 67170222Sdougb#endif 68170222Sdougb#endif 69170222Sdougb 70135446Strhodes#define CHECK(r) \ 71170222Sdougb do { \ 72135446Strhodes result = (r); \ 73170222Sdougb if (result != ISC_R_SUCCESS) \ 74170222Sdougb goto cleanup; \ 75186462Sdougb } while (0) 76135446Strhodes 77193149Sdougb#define ERR_IS_CNAME 1 78193149Sdougb#define ERR_NO_ADDRESSES 2 79193149Sdougb#define ERR_LOOKUP_FAILURE 3 80193149Sdougb#define ERR_EXTRA_A 4 81193149Sdougb#define ERR_EXTRA_AAAA 5 82193149Sdougb#define ERR_MISSING_GLUE 5 83193149Sdougb#define ERR_IS_MXCNAME 6 84193149Sdougb#define ERR_IS_SRVCNAME 7 85193149Sdougb 86135446Strhodesstatic const char *dbtype[] = { "rbt" }; 87135446Strhodes 88135446Strhodesint debug = 0; 89135446Strhodesisc_boolean_t nomerge = ISC_TRUE; 90186462Sdougb#if CHECK_LOCAL 91170222Sdougbisc_boolean_t docheckmx = ISC_TRUE; 92170222Sdougbisc_boolean_t dochecksrv = ISC_TRUE; 93170222Sdougbisc_boolean_t docheckns = ISC_TRUE; 94186462Sdougb#else 95186462Sdougbisc_boolean_t docheckmx = ISC_FALSE; 96186462Sdougbisc_boolean_t dochecksrv = ISC_FALSE; 97186462Sdougbisc_boolean_t docheckns = ISC_FALSE; 98186462Sdougb#endif 99186462Sdougbunsigned int zone_options = DNS_ZONEOPT_CHECKNS | 100170222Sdougb DNS_ZONEOPT_CHECKMX | 101143731Sdougb DNS_ZONEOPT_MANYERRORS | 102170222Sdougb DNS_ZONEOPT_CHECKNAMES | 103170222Sdougb DNS_ZONEOPT_CHECKINTEGRITY | 104186462Sdougb#if CHECK_SIBLING 105186462Sdougb DNS_ZONEOPT_CHECKSIBLING | 106186462Sdougb#endif 107170222Sdougb DNS_ZONEOPT_CHECKWILDCARD | 108170222Sdougb DNS_ZONEOPT_WARNMXCNAME | 109170222Sdougb DNS_ZONEOPT_WARNSRVCNAME; 110135446Strhodes 111170222Sdougb/* 112170222Sdougb * This needs to match the list in bin/named/log.c. 113170222Sdougb */ 114170222Sdougbstatic isc_logcategory_t categories[] = { 115170222Sdougb { "", 0 }, 116170222Sdougb { "client", 0 }, 117170222Sdougb { "network", 0 }, 118170222Sdougb { "update", 0 }, 119170222Sdougb { "queries", 0 }, 120170222Sdougb { "unmatched", 0 }, 121170222Sdougb { "update-security", 0 }, 122193149Sdougb { "query-errors", 0 }, 123170222Sdougb { NULL, 0 } 124170222Sdougb}; 125170222Sdougb 126193149Sdougbstatic isc_symtab_t *symtab = NULL; 127193149Sdougbstatic isc_mem_t *sym_mctx; 128193149Sdougb 129193149Sdougbstatic void 130193149Sdougbfreekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { 131193149Sdougb UNUSED(type); 132193149Sdougb UNUSED(value); 133193149Sdougb isc_mem_free(userarg, key); 134193149Sdougb} 135193149Sdougb 136193149Sdougbstatic void 137193149Sdougbadd(char *key, int value) { 138193149Sdougb isc_result_t result; 139193149Sdougb isc_symvalue_t symvalue; 140193149Sdougb 141193149Sdougb if (sym_mctx == NULL) { 142193149Sdougb result = isc_mem_create(0, 0, &sym_mctx); 143193149Sdougb if (result != ISC_R_SUCCESS) 144193149Sdougb return; 145193149Sdougb } 146193149Sdougb 147193149Sdougb if (symtab == NULL) { 148193149Sdougb result = isc_symtab_create(sym_mctx, 100, freekey, sym_mctx, 149193149Sdougb ISC_FALSE, &symtab); 150193149Sdougb if (result != ISC_R_SUCCESS) 151193149Sdougb return; 152193149Sdougb } 153193149Sdougb 154193149Sdougb key = isc_mem_strdup(sym_mctx, key); 155193149Sdougb if (key == NULL) 156193149Sdougb return; 157193149Sdougb 158193149Sdougb symvalue.as_pointer = NULL; 159193149Sdougb result = isc_symtab_define(symtab, key, value, symvalue, 160193149Sdougb isc_symexists_reject); 161193149Sdougb if (result != ISC_R_SUCCESS) 162193149Sdougb isc_mem_free(sym_mctx, key); 163193149Sdougb} 164193149Sdougb 165170222Sdougbstatic isc_boolean_t 166193149Sdougblogged(char *key, int value) { 167193149Sdougb isc_result_t result; 168193149Sdougb 169193149Sdougb if (symtab == NULL) 170193149Sdougb return (ISC_FALSE); 171193149Sdougb 172193149Sdougb result = isc_symtab_lookup(symtab, key, value, NULL); 173193149Sdougb if (result == ISC_R_SUCCESS) 174193149Sdougb return (ISC_TRUE); 175193149Sdougb return (ISC_FALSE); 176193149Sdougb} 177193149Sdougb 178193149Sdougbstatic isc_boolean_t 179170222Sdougbcheckns(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner, 180170222Sdougb dns_rdataset_t *a, dns_rdataset_t *aaaa) 181170222Sdougb{ 182170222Sdougb#ifdef USE_GETADDRINFO 183170222Sdougb dns_rdataset_t *rdataset; 184170222Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 185170222Sdougb struct addrinfo hints, *ai, *cur; 186170222Sdougb char namebuf[DNS_NAME_FORMATSIZE + 1]; 187170222Sdougb char ownerbuf[DNS_NAME_FORMATSIZE]; 188170222Sdougb char addrbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123")]; 189170222Sdougb isc_boolean_t answer = ISC_TRUE; 190170222Sdougb isc_boolean_t match; 191170222Sdougb const char *type; 192170222Sdougb void *ptr = NULL; 193170222Sdougb int result; 194170222Sdougb 195170222Sdougb REQUIRE(a == NULL || !dns_rdataset_isassociated(a) || 196170222Sdougb a->type == dns_rdatatype_a); 197170222Sdougb REQUIRE(aaaa == NULL || !dns_rdataset_isassociated(aaaa) || 198170222Sdougb aaaa->type == dns_rdatatype_aaaa); 199254402Serwin 200254402Serwin if (a == NULL || aaaa == NULL) 201254402Serwin return (answer); 202254402Serwin 203170222Sdougb memset(&hints, 0, sizeof(hints)); 204170222Sdougb hints.ai_flags = AI_CANONNAME; 205170222Sdougb hints.ai_family = PF_UNSPEC; 206170222Sdougb hints.ai_socktype = SOCK_STREAM; 207170222Sdougb hints.ai_protocol = IPPROTO_TCP; 208170222Sdougb 209170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 210170222Sdougb /* 211170222Sdougb * Turn off search. 212170222Sdougb */ 213170222Sdougb if (dns_name_countlabels(name) > 1U) 214170222Sdougb strcat(namebuf, "."); 215170222Sdougb dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); 216186462Sdougb 217170222Sdougb result = getaddrinfo(namebuf, NULL, &hints, &ai); 218170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 219170222Sdougb switch (result) { 220170222Sdougb case 0: 221174187Sdougb /* 222174187Sdougb * Work around broken getaddrinfo() implementations that 223174187Sdougb * fail to set ai_canonname on first entry. 224174187Sdougb */ 225174187Sdougb cur = ai; 226174187Sdougb while (cur != NULL && cur->ai_canonname == NULL && 227174187Sdougb cur->ai_next != NULL) 228174187Sdougb cur = cur->ai_next; 229174187Sdougb if (cur != NULL && cur->ai_canonname != NULL && 230193149Sdougb strcasecmp(cur->ai_canonname, namebuf) != 0 && 231193149Sdougb !logged(namebuf, ERR_IS_CNAME)) { 232170222Sdougb dns_zone_log(zone, ISC_LOG_ERROR, 233170222Sdougb "%s/NS '%s' (out of zone) " 234193149Sdougb "is a CNAME '%s' (illegal)", 235193149Sdougb ownerbuf, namebuf, 236193149Sdougb cur->ai_canonname); 237170222Sdougb /* XXX950 make fatal for 9.5.0 */ 238170222Sdougb /* answer = ISC_FALSE; */ 239193149Sdougb add(namebuf, ERR_IS_CNAME); 240170222Sdougb } 241170222Sdougb break; 242170222Sdougb case EAI_NONAME: 243170222Sdougb#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 244170222Sdougb case EAI_NODATA: 245170222Sdougb#endif 246193149Sdougb if (!logged(namebuf, ERR_NO_ADDRESSES)) { 247193149Sdougb dns_zone_log(zone, ISC_LOG_ERROR, 248193149Sdougb "%s/NS '%s' (out of zone) " 249193149Sdougb "has no addresses records (A or AAAA)", 250193149Sdougb ownerbuf, namebuf); 251193149Sdougb add(namebuf, ERR_NO_ADDRESSES); 252193149Sdougb } 253170222Sdougb /* XXX950 make fatal for 9.5.0 */ 254170222Sdougb return (ISC_TRUE); 255170222Sdougb 256170222Sdougb default: 257193149Sdougb if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { 258193149Sdougb dns_zone_log(zone, ISC_LOG_WARNING, 259193149Sdougb "getaddrinfo(%s) failed: %s", 260193149Sdougb namebuf, gai_strerror(result)); 261193149Sdougb add(namebuf, ERR_LOOKUP_FAILURE); 262193149Sdougb } 263170222Sdougb return (ISC_TRUE); 264170222Sdougb } 265254402Serwin 266170222Sdougb /* 267170222Sdougb * Check that all glue records really exist. 268170222Sdougb */ 269170222Sdougb if (!dns_rdataset_isassociated(a)) 270170222Sdougb goto checkaaaa; 271170222Sdougb result = dns_rdataset_first(a); 272170222Sdougb while (result == ISC_R_SUCCESS) { 273170222Sdougb dns_rdataset_current(a, &rdata); 274170222Sdougb match = ISC_FALSE; 275170222Sdougb for (cur = ai; cur != NULL; cur = cur->ai_next) { 276170222Sdougb if (cur->ai_family != AF_INET) 277170222Sdougb continue; 278170222Sdougb ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; 279170222Sdougb if (memcmp(ptr, rdata.data, rdata.length) == 0) { 280170222Sdougb match = ISC_TRUE; 281170222Sdougb break; 282170222Sdougb } 283170222Sdougb } 284193149Sdougb if (!match && !logged(namebuf, ERR_EXTRA_A)) { 285170222Sdougb dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " 286170222Sdougb "extra GLUE A record (%s)", 287170222Sdougb ownerbuf, namebuf, 288170222Sdougb inet_ntop(AF_INET, rdata.data, 289170222Sdougb addrbuf, sizeof(addrbuf))); 290193149Sdougb add(namebuf, ERR_EXTRA_A); 291170222Sdougb /* XXX950 make fatal for 9.5.0 */ 292170222Sdougb /* answer = ISC_FALSE; */ 293170222Sdougb } 294170222Sdougb dns_rdata_reset(&rdata); 295170222Sdougb result = dns_rdataset_next(a); 296170222Sdougb } 297170222Sdougb 298170222Sdougb checkaaaa: 299170222Sdougb if (!dns_rdataset_isassociated(aaaa)) 300170222Sdougb goto checkmissing; 301170222Sdougb result = dns_rdataset_first(aaaa); 302170222Sdougb while (result == ISC_R_SUCCESS) { 303170222Sdougb dns_rdataset_current(aaaa, &rdata); 304170222Sdougb match = ISC_FALSE; 305170222Sdougb for (cur = ai; cur != NULL; cur = cur->ai_next) { 306170222Sdougb if (cur->ai_family != AF_INET6) 307170222Sdougb continue; 308170222Sdougb ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; 309170222Sdougb if (memcmp(ptr, rdata.data, rdata.length) == 0) { 310170222Sdougb match = ISC_TRUE; 311170222Sdougb break; 312170222Sdougb } 313170222Sdougb } 314193149Sdougb if (!match && !logged(namebuf, ERR_EXTRA_AAAA)) { 315170222Sdougb dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " 316170222Sdougb "extra GLUE AAAA record (%s)", 317170222Sdougb ownerbuf, namebuf, 318170222Sdougb inet_ntop(AF_INET6, rdata.data, 319170222Sdougb addrbuf, sizeof(addrbuf))); 320193149Sdougb add(namebuf, ERR_EXTRA_AAAA); 321170222Sdougb /* XXX950 make fatal for 9.5.0. */ 322170222Sdougb /* answer = ISC_FALSE; */ 323170222Sdougb } 324170222Sdougb dns_rdata_reset(&rdata); 325170222Sdougb result = dns_rdataset_next(aaaa); 326170222Sdougb } 327170222Sdougb 328170222Sdougb checkmissing: 329170222Sdougb /* 330170222Sdougb * Check that all addresses appear in the glue. 331170222Sdougb */ 332193149Sdougb if (!logged(namebuf, ERR_MISSING_GLUE)) { 333193149Sdougb isc_boolean_t missing_glue = ISC_FALSE; 334193149Sdougb for (cur = ai; cur != NULL; cur = cur->ai_next) { 335193149Sdougb switch (cur->ai_family) { 336193149Sdougb case AF_INET: 337193149Sdougb rdataset = a; 338193149Sdougb ptr = &((struct sockaddr_in *)(cur->ai_addr))->sin_addr; 339193149Sdougb type = "A"; 340193149Sdougb break; 341193149Sdougb case AF_INET6: 342193149Sdougb rdataset = aaaa; 343193149Sdougb ptr = &((struct sockaddr_in6 *)(cur->ai_addr))->sin6_addr; 344193149Sdougb type = "AAAA"; 345193149Sdougb break; 346193149Sdougb default: 347193149Sdougb continue; 348193149Sdougb } 349193149Sdougb match = ISC_FALSE; 350193149Sdougb if (dns_rdataset_isassociated(rdataset)) 351193149Sdougb result = dns_rdataset_first(rdataset); 352193149Sdougb else 353193149Sdougb result = ISC_R_FAILURE; 354193149Sdougb while (result == ISC_R_SUCCESS && !match) { 355193149Sdougb dns_rdataset_current(rdataset, &rdata); 356193149Sdougb if (memcmp(ptr, rdata.data, rdata.length) == 0) 357193149Sdougb match = ISC_TRUE; 358193149Sdougb dns_rdata_reset(&rdata); 359193149Sdougb result = dns_rdataset_next(rdataset); 360193149Sdougb } 361193149Sdougb if (!match) { 362193149Sdougb dns_zone_log(zone, ISC_LOG_ERROR, "%s/NS '%s' " 363193149Sdougb "missing GLUE %s record (%s)", 364193149Sdougb ownerbuf, namebuf, type, 365193149Sdougb inet_ntop(cur->ai_family, ptr, 366193149Sdougb addrbuf, sizeof(addrbuf))); 367193149Sdougb /* XXX950 make fatal for 9.5.0. */ 368193149Sdougb /* answer = ISC_FALSE; */ 369193149Sdougb missing_glue = ISC_TRUE; 370193149Sdougb } 371170222Sdougb } 372193149Sdougb if (missing_glue) 373193149Sdougb add(namebuf, ERR_MISSING_GLUE); 374170222Sdougb } 375170222Sdougb freeaddrinfo(ai); 376170222Sdougb return (answer); 377170222Sdougb#else 378170222Sdougb return (ISC_TRUE); 379170222Sdougb#endif 380170222Sdougb} 381170222Sdougb 382170222Sdougbstatic isc_boolean_t 383170222Sdougbcheckmx(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) { 384170222Sdougb#ifdef USE_GETADDRINFO 385174187Sdougb struct addrinfo hints, *ai, *cur; 386170222Sdougb char namebuf[DNS_NAME_FORMATSIZE + 1]; 387170222Sdougb char ownerbuf[DNS_NAME_FORMATSIZE]; 388170222Sdougb int result; 389170222Sdougb int level = ISC_LOG_ERROR; 390170222Sdougb isc_boolean_t answer = ISC_TRUE; 391170222Sdougb 392170222Sdougb memset(&hints, 0, sizeof(hints)); 393170222Sdougb hints.ai_flags = AI_CANONNAME; 394170222Sdougb hints.ai_family = PF_UNSPEC; 395170222Sdougb hints.ai_socktype = SOCK_STREAM; 396170222Sdougb hints.ai_protocol = IPPROTO_TCP; 397170222Sdougb 398170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 399170222Sdougb /* 400170222Sdougb * Turn off search. 401170222Sdougb */ 402170222Sdougb if (dns_name_countlabels(name) > 1U) 403170222Sdougb strcat(namebuf, "."); 404170222Sdougb dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); 405186462Sdougb 406170222Sdougb result = getaddrinfo(namebuf, NULL, &hints, &ai); 407170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 408170222Sdougb switch (result) { 409170222Sdougb case 0: 410174187Sdougb /* 411174187Sdougb * Work around broken getaddrinfo() implementations that 412174187Sdougb * fail to set ai_canonname on first entry. 413174187Sdougb */ 414174187Sdougb cur = ai; 415174187Sdougb while (cur != NULL && cur->ai_canonname == NULL && 416174187Sdougb cur->ai_next != NULL) 417174187Sdougb cur = cur->ai_next; 418174187Sdougb if (cur != NULL && cur->ai_canonname != NULL && 419174187Sdougb strcasecmp(cur->ai_canonname, namebuf) != 0) { 420170222Sdougb if ((zone_options & DNS_ZONEOPT_WARNMXCNAME) != 0) 421170222Sdougb level = ISC_LOG_WARNING; 422170222Sdougb if ((zone_options & DNS_ZONEOPT_IGNOREMXCNAME) == 0) { 423193149Sdougb if (!logged(namebuf, ERR_IS_MXCNAME)) { 424193149Sdougb dns_zone_log(zone, level, 425193149Sdougb "%s/MX '%s' (out of zone)" 426193149Sdougb " is a CNAME '%s' " 427193149Sdougb "(illegal)", 428193149Sdougb ownerbuf, namebuf, 429193149Sdougb cur->ai_canonname); 430193149Sdougb add(namebuf, ERR_IS_MXCNAME); 431193149Sdougb } 432170222Sdougb if (level == ISC_LOG_ERROR) 433170222Sdougb answer = ISC_FALSE; 434170222Sdougb } 435170222Sdougb } 436170222Sdougb freeaddrinfo(ai); 437170222Sdougb return (answer); 438170222Sdougb 439170222Sdougb case EAI_NONAME: 440170222Sdougb#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 441170222Sdougb case EAI_NODATA: 442170222Sdougb#endif 443193149Sdougb if (!logged(namebuf, ERR_NO_ADDRESSES)) { 444193149Sdougb dns_zone_log(zone, ISC_LOG_ERROR, 445193149Sdougb "%s/MX '%s' (out of zone) " 446193149Sdougb "has no addresses records (A or AAAA)", 447193149Sdougb ownerbuf, namebuf); 448193149Sdougb add(namebuf, ERR_NO_ADDRESSES); 449193149Sdougb } 450170222Sdougb /* XXX950 make fatal for 9.5.0. */ 451170222Sdougb return (ISC_TRUE); 452170222Sdougb 453170222Sdougb default: 454193149Sdougb if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { 455193149Sdougb dns_zone_log(zone, ISC_LOG_WARNING, 456170222Sdougb "getaddrinfo(%s) failed: %s", 457170222Sdougb namebuf, gai_strerror(result)); 458193149Sdougb add(namebuf, ERR_LOOKUP_FAILURE); 459193149Sdougb } 460170222Sdougb return (ISC_TRUE); 461170222Sdougb } 462170222Sdougb#else 463170222Sdougb return (ISC_TRUE); 464170222Sdougb#endif 465170222Sdougb} 466170222Sdougb 467170222Sdougbstatic isc_boolean_t 468170222Sdougbchecksrv(dns_zone_t *zone, dns_name_t *name, dns_name_t *owner) { 469170222Sdougb#ifdef USE_GETADDRINFO 470174187Sdougb struct addrinfo hints, *ai, *cur; 471170222Sdougb char namebuf[DNS_NAME_FORMATSIZE + 1]; 472170222Sdougb char ownerbuf[DNS_NAME_FORMATSIZE]; 473170222Sdougb int result; 474170222Sdougb int level = ISC_LOG_ERROR; 475170222Sdougb isc_boolean_t answer = ISC_TRUE; 476170222Sdougb 477170222Sdougb memset(&hints, 0, sizeof(hints)); 478170222Sdougb hints.ai_flags = AI_CANONNAME; 479170222Sdougb hints.ai_family = PF_UNSPEC; 480170222Sdougb hints.ai_socktype = SOCK_STREAM; 481170222Sdougb hints.ai_protocol = IPPROTO_TCP; 482170222Sdougb 483170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 484170222Sdougb /* 485170222Sdougb * Turn off search. 486170222Sdougb */ 487170222Sdougb if (dns_name_countlabels(name) > 1U) 488170222Sdougb strcat(namebuf, "."); 489170222Sdougb dns_name_format(owner, ownerbuf, sizeof(ownerbuf)); 490186462Sdougb 491170222Sdougb result = getaddrinfo(namebuf, NULL, &hints, &ai); 492170222Sdougb dns_name_format(name, namebuf, sizeof(namebuf) - 1); 493170222Sdougb switch (result) { 494170222Sdougb case 0: 495174187Sdougb /* 496174187Sdougb * Work around broken getaddrinfo() implementations that 497174187Sdougb * fail to set ai_canonname on first entry. 498174187Sdougb */ 499174187Sdougb cur = ai; 500174187Sdougb while (cur != NULL && cur->ai_canonname == NULL && 501174187Sdougb cur->ai_next != NULL) 502174187Sdougb cur = cur->ai_next; 503174187Sdougb if (cur != NULL && cur->ai_canonname != NULL && 504174187Sdougb strcasecmp(cur->ai_canonname, namebuf) != 0) { 505170222Sdougb if ((zone_options & DNS_ZONEOPT_WARNSRVCNAME) != 0) 506170222Sdougb level = ISC_LOG_WARNING; 507170222Sdougb if ((zone_options & DNS_ZONEOPT_IGNORESRVCNAME) == 0) { 508193149Sdougb if (!logged(namebuf, ERR_IS_SRVCNAME)) { 509193149Sdougb dns_zone_log(zone, level, "%s/SRV '%s'" 510193149Sdougb " (out of zone) is a " 511193149Sdougb "CNAME '%s' (illegal)", 512193149Sdougb ownerbuf, namebuf, 513193149Sdougb cur->ai_canonname); 514193149Sdougb add(namebuf, ERR_IS_SRVCNAME); 515193149Sdougb } 516170222Sdougb if (level == ISC_LOG_ERROR) 517170222Sdougb answer = ISC_FALSE; 518170222Sdougb } 519170222Sdougb } 520170222Sdougb freeaddrinfo(ai); 521170222Sdougb return (answer); 522170222Sdougb 523170222Sdougb case EAI_NONAME: 524170222Sdougb#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 525170222Sdougb case EAI_NODATA: 526170222Sdougb#endif 527193149Sdougb if (!logged(namebuf, ERR_NO_ADDRESSES)) { 528193149Sdougb dns_zone_log(zone, ISC_LOG_ERROR, 529193149Sdougb "%s/SRV '%s' (out of zone) " 530193149Sdougb "has no addresses records (A or AAAA)", 531193149Sdougb ownerbuf, namebuf); 532193149Sdougb add(namebuf, ERR_NO_ADDRESSES); 533193149Sdougb } 534170222Sdougb /* XXX950 make fatal for 9.5.0. */ 535170222Sdougb return (ISC_TRUE); 536170222Sdougb 537170222Sdougb default: 538193149Sdougb if (!logged(namebuf, ERR_LOOKUP_FAILURE)) { 539193149Sdougb dns_zone_log(zone, ISC_LOG_WARNING, 540193149Sdougb "getaddrinfo(%s) failed: %s", 541193149Sdougb namebuf, gai_strerror(result)); 542193149Sdougb add(namebuf, ERR_LOOKUP_FAILURE); 543193149Sdougb } 544170222Sdougb return (ISC_TRUE); 545170222Sdougb } 546170222Sdougb#else 547170222Sdougb return (ISC_TRUE); 548170222Sdougb#endif 549170222Sdougb} 550170222Sdougb 551135446Strhodesisc_result_t 552193149Sdougbsetup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) { 553135446Strhodes isc_logdestination_t destination; 554135446Strhodes isc_logconfig_t *logconfig = NULL; 555135446Strhodes isc_log_t *log = NULL; 556135446Strhodes 557135446Strhodes RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS); 558170222Sdougb isc_log_registercategories(log, categories); 559135446Strhodes isc_log_setcontext(log); 560170222Sdougb dns_log_init(log); 561170222Sdougb dns_log_setcontext(log); 562170222Sdougb cfg_log_init(log); 563135446Strhodes 564193149Sdougb destination.file.stream = errout; 565135446Strhodes destination.file.name = NULL; 566135446Strhodes destination.file.versions = ISC_LOG_ROLLNEVER; 567135446Strhodes destination.file.maximum_size = 0; 568135446Strhodes RUNTIME_CHECK(isc_log_createchannel(logconfig, "stderr", 569135446Strhodes ISC_LOG_TOFILEDESC, 570135446Strhodes ISC_LOG_DYNAMIC, 571135446Strhodes &destination, 0) == ISC_R_SUCCESS); 572135446Strhodes RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", 573135446Strhodes NULL, NULL) == ISC_R_SUCCESS); 574135446Strhodes 575135446Strhodes *logp = log; 576135446Strhodes return (ISC_R_SUCCESS); 577135446Strhodes} 578135446Strhodes 579170222Sdougb/*% load the zone */ 580135446Strhodesisc_result_t 581135446Strhodesload_zone(isc_mem_t *mctx, const char *zonename, const char *filename, 582170222Sdougb dns_masterformat_t fileformat, const char *classname, 583170222Sdougb dns_zone_t **zonep) 584135446Strhodes{ 585135446Strhodes isc_result_t result; 586135446Strhodes dns_rdataclass_t rdclass; 587135446Strhodes isc_textregion_t region; 588135446Strhodes isc_buffer_t buffer; 589135446Strhodes dns_fixedname_t fixorigin; 590135446Strhodes dns_name_t *origin; 591135446Strhodes dns_zone_t *zone = NULL; 592135446Strhodes 593135446Strhodes REQUIRE(zonep == NULL || *zonep == NULL); 594135446Strhodes 595135446Strhodes if (debug) 596135446Strhodes fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n", 597135446Strhodes zonename, filename, classname); 598135446Strhodes 599135446Strhodes CHECK(dns_zone_create(&zone, mctx)); 600135446Strhodes 601135446Strhodes dns_zone_settype(zone, dns_zone_master); 602135446Strhodes 603254402Serwin isc_buffer_constinit(&buffer, zonename, strlen(zonename)); 604135446Strhodes isc_buffer_add(&buffer, strlen(zonename)); 605135446Strhodes dns_fixedname_init(&fixorigin); 606135446Strhodes origin = dns_fixedname_name(&fixorigin); 607224092Sdougb CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); 608135446Strhodes CHECK(dns_zone_setorigin(zone, origin)); 609135446Strhodes CHECK(dns_zone_setdbtype(zone, 1, (const char * const *) dbtype)); 610170222Sdougb CHECK(dns_zone_setfile2(zone, filename, fileformat)); 611135446Strhodes 612135446Strhodes DE_CONST(classname, region.base); 613135446Strhodes region.length = strlen(classname); 614135446Strhodes CHECK(dns_rdataclass_fromtext(&rdclass, ®ion)); 615135446Strhodes 616135446Strhodes dns_zone_setclass(zone, rdclass); 617135446Strhodes dns_zone_setoption(zone, zone_options, ISC_TRUE); 618135446Strhodes dns_zone_setoption(zone, DNS_ZONEOPT_NOMERGE, nomerge); 619170222Sdougb if (docheckmx) 620170222Sdougb dns_zone_setcheckmx(zone, checkmx); 621170222Sdougb if (docheckns) 622170222Sdougb dns_zone_setcheckns(zone, checkns); 623170222Sdougb if (dochecksrv) 624170222Sdougb dns_zone_setchecksrv(zone, checksrv); 625135446Strhodes 626135446Strhodes CHECK(dns_zone_load(zone)); 627170222Sdougb if (zonep != NULL) { 628135446Strhodes *zonep = zone; 629135446Strhodes zone = NULL; 630135446Strhodes } 631135446Strhodes 632135446Strhodes cleanup: 633135446Strhodes if (zone != NULL) 634135446Strhodes dns_zone_detach(&zone); 635135446Strhodes return (result); 636135446Strhodes} 637135446Strhodes 638170222Sdougb/*% dump the zone */ 639135446Strhodesisc_result_t 640170222Sdougbdump_zone(const char *zonename, dns_zone_t *zone, const char *filename, 641254897Serwin dns_masterformat_t fileformat, const dns_master_style_t *style, 642254897Serwin const isc_uint32_t rawversion) 643135446Strhodes{ 644135446Strhodes isc_result_t result; 645135446Strhodes FILE *output = stdout; 646245163Serwin const char *flags; 647135446Strhodes 648245163Serwin flags = (fileformat == dns_masterformat_text) ? "w+" : "wb+"; 649245163Serwin 650135446Strhodes if (debug) { 651193149Sdougb if (filename != NULL && strcmp(filename, "-") != 0) 652135446Strhodes fprintf(stderr, "dumping \"%s\" to \"%s\"\n", 653135446Strhodes zonename, filename); 654135446Strhodes else 655135446Strhodes fprintf(stderr, "dumping \"%s\"\n", zonename); 656135446Strhodes } 657135446Strhodes 658193149Sdougb if (filename != NULL && strcmp(filename, "-") != 0) { 659245163Serwin result = isc_stdio_open(filename, flags, &output); 660135446Strhodes 661135446Strhodes if (result != ISC_R_SUCCESS) { 662135446Strhodes fprintf(stderr, "could not open output " 663135446Strhodes "file \"%s\" for writing\n", filename); 664135446Strhodes return (ISC_R_FAILURE); 665135446Strhodes } 666135446Strhodes } 667135446Strhodes 668254897Serwin result = dns_zone_dumptostream3(zone, output, fileformat, style, 669254897Serwin rawversion); 670193149Sdougb if (output != stdout) 671135446Strhodes (void)isc_stdio_close(output); 672135446Strhodes 673135446Strhodes return (result); 674135446Strhodes} 675216175Sdougb 676216175Sdougb#ifdef _WIN32 677216175Sdougbvoid 678216175SdougbInitSockets(void) { 679216175Sdougb WORD wVersionRequested; 680216175Sdougb WSADATA wsaData; 681216175Sdougb int err; 682216175Sdougb 683216175Sdougb wVersionRequested = MAKEWORD(2, 0); 684216175Sdougb 685216175Sdougb err = WSAStartup( wVersionRequested, &wsaData ); 686216175Sdougb if (err != 0) { 687216175Sdougb fprintf(stderr, "WSAStartup() failed: %d\n", err); 688216175Sdougb exit(1); 689216175Sdougb } 690216175Sdougb} 691216175Sdougb 692216175Sdougbvoid 693216175SdougbDestroySockets(void) { 694216175Sdougb WSACleanup(); 695216175Sdougb} 696216175Sdougb#endif 697216175Sdougb 698