static void dump_symboltable(void) { int i; isc_result_t result; const char *fname; const void *addr; if (isc__backtrace_nsymbols == 0) return; if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99))) return; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), "Symbol table:"); for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) { addr = NULL; fname = NULL; result = isc_backtrace_getsymbolfromindex(i, &addr, &fname); if (result == ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), "[%d] %p %s", i, addr, fname); } } }
static void try_dscp_v6(void) { #ifdef ISC_PLATFORM_HAVEIPV6 #ifdef WANT_IPV6 #ifdef IPV6_TCLASS char strbuf[ISC_STRERRORSIZE]; struct addrinfo hints, *res0; int s, dscp = 0, n; #if defined(IPV6_RECVTCLASS) int on = 1; #endif /* IPV6_RECVTCLASS */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; #ifdef AI_NUMERICHOST hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; #else hints.ai_flags = AI_PASSIVE; #endif n = getaddrinfo("::1", NULL, &hints, &res0); if (n != 0 || res0 == NULL) { isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), "getaddrinfo(::1): %s", gai_strerror(n)); return; } s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol); if (s == -1) { isc__strerror(errno, strbuf, sizeof(strbuf)); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), "socket: %s", strbuf); freeaddrinfo(res0); return; } if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0) dscp_result |= ISC_NET_DSCPSETV6; #ifdef IPV6_RECVTCLASS on = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0) dscp_result |= ISC_NET_DSCPRECVV6; #endif /* IPV6_RECVTCLASS */ #ifdef ISC_NET_BSD44MSGHDR if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0)) dscp_result |= ISC_NET_DSCPPKTV6; #endif /* ISC_NET_BSD44MSGHDR */ freeaddrinfo(res0); close(s); #endif /* IPV6_TCLASS */ #endif /* WANT_IPV6 */ #endif /* ISC_PLATFORM_HAVEIPV6 */ }
void dns_dlzdestroy(dns_dlzdb_t **dbp) { isc_mem_t *mctx; dns_dlzdestroy_t destroy; /* Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Unloading DLZ driver."); /* * Perform checks to make sure data is as we expect it to be. */ REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp)); #ifdef BIND9 if ((*dbp)->ssutable != NULL) { dns_ssutable_detach(&(*dbp)->ssutable); } #endif /* call the drivers destroy method */ if ((*dbp) != NULL) { mctx = (*dbp)->mctx; destroy = (*dbp)->implementation->methods->destroy; (*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata); /* return memory */ isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t)); isc_mem_detach(&mctx); } *dbp = NULL; }
/*% * Wrapper around dns_sdlzregister(). */ isc_result_t dlz_mysql_init(void) { isc_result_t result; /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Registering DLZ mysql driver."); /* Driver is always threadsafe. Because of the way MySQL handles * threads the MySQL driver can only be used when bind is run single * threaded. Using MySQL with Bind running multi-threaded is not * allowed. When using the MySQL driver "-n1" should always be * passed to Bind to guarantee single threaded operation. */ result = dns_sdlzregister("mysql", &dlz_mysql_methods, NULL, DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA | DNS_SDLZFLAG_THREADSAFE, ns_g_mctx, &dlz_mysql); /* if we can't register the driver, there are big problems. */ if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "dns_sdlzregister() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; } return result; }
void dns_dlzdestroy(dns_dlzdb_t **dbp) { dns_dlzdestroy_t destroy; dns_dlzdb_t *db; /* Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Unloading DLZ driver."); /* * Perform checks to make sure data is as we expect it to be. */ REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp)); db = *dbp; *dbp = NULL; if (db->ssutable != NULL) dns_ssutable_detach(&db->ssutable); /* call the drivers destroy method */ if (db->dlzname != NULL) isc_mem_free(db->mctx, db->dlzname); destroy = db->implementation->methods->destroy; (*destroy)(db->implementation->driverarg, db->dbdata); /* return memory and detach */ isc_mem_putanddetach(&db->mctx, db, sizeof(dns_dlzdb_t)); }
/*% * Wrapper around dns_sdlzregister(). */ isc_result_t dlz_postgres_init(void) { isc_result_t result; /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Registering DLZ postgres driver."); /* * Driver is always threadsafe. When multithreaded all * functions use multithreaded code. When not multithreaded, * all functions can only be entered once, but only 1 thread * of operation is available in Bind. So everything is still * threadsafe. */ result = dns_sdlzregister("postgres", &dlz_postgres_methods, NULL, DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA | DNS_SDLZFLAG_THREADSAFE, ns_g_mctx, &dlz_postgres); /* if we can't register the driver, there are big problems. */ if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "dns_sdlzregister() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; } return result; }
/*% * Wrapper around dns_sdlzregister(). */ isc_result_t dlz_bdbhpt_init(void) { isc_result_t result; /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Registering DLZ bdbhpt driver."); result = dns_sdlzregister("bdbhpt", &dlz_bdbhpt_methods, NULL, DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA | DNS_SDLZFLAG_THREADSAFE, ns_g_mctx, &dlz_bdbhpt); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "dns_sdlzregister() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; } return result; }
static void ssu_e_log (int level, const char *fmt, ...) { va_list ap; va_start (ap, fmt); isc_log_vwrite (dns_lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG (level), fmt, ap); va_end (ap); }
static void tkey_log (const char *fmt, ...) { va_list ap; va_start (ap, fmt); isc_log_vwrite (dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, ISC_LOG_DEBUG (4), fmt, ap); va_end (ap); }
int supervisor_destroy(supervisor_t *sv) { zmq_close(sv->zmq_sock_rpc); zmq_ctx_destroy(sv->zmq_ctx); free(sv); supervisor_log(ISC_LOG_DEBUG(1), "supervisor destroyed"); return 0; }
static isc_result_t freezezones(dns_zone_t *zone, void *uap) { isc_boolean_t freeze = *(isc_boolean_t *)uap; isc_boolean_t frozen; isc_result_t result = ISC_R_SUCCESS; char classstr[DNS_RDATACLASS_FORMATSIZE]; char zonename[DNS_NAME_FORMATSIZE]; dns_view_t *view; char *journal; const char *vname; const char *sep; int level; if (dns_zone_gettype(zone) != dns_zone_master) return (ISC_R_SUCCESS); frozen = dns_zone_getupdatedisabled(zone); if (freeze) { if (frozen) result = DNS_R_FROZEN; if (result == ISC_R_SUCCESS) result = dns_zone_flush(zone); if (result == ISC_R_SUCCESS) { journal = dns_zone_getjournal(zone); if (journal != NULL) (void)isc_file_remove(journal); } } else { if (frozen) { result = dns_zone_load(zone); if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE) result = ISC_R_SUCCESS; } } if (result == ISC_R_SUCCESS) dns_zone_setupdatedisabled(zone, freeze); view = dns_zone_getview(zone); if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_default") == 0) { vname = ""; sep = ""; } else { vname = view->name; sep = " "; } dns_rdataclass_format(dns_zone_getclass(zone), classstr, sizeof(classstr)); dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, level, "%s zone '%s/%s'%s%s: %s", freeze ? "freezing" : "thawing", zonename, classstr, sep, vname, isc_result_totext(result)); return (result); }
/* * Log a message at the given level. */ static void dlopen_log(int level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level), fmt, ap); va_end(ap); }
void gss_log(int level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_TKEY, ISC_LOG_DEBUG(level), fmt, ap); va_end(ap); }
void setup_logging (int verbose, isc_mem_t * mctx, isc_log_t ** logp) { isc_result_t result; isc_logdestination_t destination; isc_logconfig_t *logconfig = NULL; isc_log_t *log = NULL; int level; if (verbose < 0) verbose = 0; switch (verbose) { case 0: /* * We want to see warnings about things like out-of-zone * data in the master file even when not verbose. */ level = ISC_LOG_WARNING; break; case 1: level = ISC_LOG_INFO; break; default: level = ISC_LOG_DEBUG (verbose - 2 + 1); break; } RUNTIME_CHECK (isc_log_create (mctx, &log, &logconfig) == ISC_R_SUCCESS); isc_log_setcontext (log); dns_log_init (log); dns_log_setcontext (log); RUNTIME_CHECK (isc_log_settag (logconfig, program) == ISC_R_SUCCESS); /* * Set up a channel similar to default_stderr except: * - the logging level is passed in * - the program name and logging level are printed * - no time stamp is printed */ destination.file.stream = stderr; destination.file.name = NULL; destination.file.versions = ISC_LOG_ROLLNEVER; destination.file.maximum_size = 0; result = isc_log_createchannel (logconfig, "stderr", ISC_LOG_TOFILEDESC, level, &destination, ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL); check_result (result, "isc_log_createchannel()"); RUNTIME_CHECK (isc_log_usechannel (logconfig, "stderr", NULL, NULL) == ISC_R_SUCCESS); *logp = log; }
void ns_lwdclient_log(int level, const char *format, ...) { va_list args; va_start(args, format); isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, ISC_LOG_DEBUG(level), format, args); va_end(args); }
/*% * Wrapper around dns_sdlzunregister(). */ void dlz_ldap_clear (void) { /* * Write debugging message to log */ isc_log_write (dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG (2), "Unregistering DLZ ldap driver."); if (dlz_ldap != NULL) dns_sdlzunregister (&dlz_ldap); }
/*% * Wrapper around dns_sdlzunregister(). */ void dlz_odbc_clear (void) { /* * Write debugging message to log */ isc_log_write (dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG (2), "Unregistering DLZ odbc driver."); /* unregister the driver. */ if (dlz_odbc != NULL) dns_sdlzunregister (&dlz_odbc); }
static void setup_seccomp() { scmp_filter_ctx ctx; unsigned int i; int ret; /* Make sure the lists are in sync */ INSIST((sizeof(scmp_syscalls) / sizeof(int)) == (sizeof(scmp_syscall_names) / sizeof(const char *))); ctx = seccomp_init(SCMP_ACT_KILL); if (ctx == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp activation failed"); return; } for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) { ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, scmp_syscalls[i], 0); if (ret < 0) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp rule failed: %s", scmp_syscall_names[i]); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9), "added libseccomp rule: %s", scmp_syscall_names[i]); } ret = seccomp_load(ctx); if (ret < 0) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_WARNING, "libseccomp unable to load filter"); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, "libseccomp sandboxing active"); } /* * Release filter in ctx. Filters already loaded are not * affected. */ seccomp_release(ctx); }
static isc_result_t listener_startclients(ns_lwreslistener_t *listener) { ns_lwdclientmgr_t *cm; unsigned int i; isc_result_t result = ISC_R_SUCCESS; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, ISC_LOG_DEBUG(6), "listener_startclients: creating %d " "managers with %d clients each", listener->manager->ntasks, listener->manager->nclients); /* * Create the client managers. */ for (i = 0; i < listener->manager->ntasks; i++) { result = ns_lwdclientmgr_create(listener, listener->manager->nclients, ns_g_taskmgr); if (result != ISC_R_SUCCESS) break; } /* * Ensure that we have created at least one. */ if (ISC_LIST_EMPTY(listener->cmgrs)) return (result); /* * Walk the list of clients and start each one up. */ LOCK(&listener->lock); cm = ISC_LIST_HEAD(listener->cmgrs); while (cm != NULL) { result = ns_lwdclient_startrecv(cm); if (result != ISC_R_SUCCESS) isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, "could not start lwres " "client handler: %s", isc_result_totext(result)); cm = ISC_LIST_NEXT(cm, link); } UNLOCK(&listener->lock); return (ISC_R_SUCCESS); }
static isc_result_t stub_dlz_findzonedb(void *driverarg, void *dbdata, const char *name) { config_data_t *cd; UNUSED(driverarg); cd = (config_data_t *) dbdata; /* Write info message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "dlz_stub findzone looking for '%s'", name); if (strcmp(cd->myzone, name) == 0) return (ISC_R_SUCCESS); else return (ISC_R_NOTFOUND); }
static void ldapdb_bind(const char *zone, struct ldapdb_data *data, LDAP **ldp) { #ifndef LDAPDB_RFC1823API const int ver = LDAPDB_LDAP_VERSION; #endif int failure = 1, counter = 1, rc; /* Make sure we try at least three times to connect+bind * to the LDAP server. Sleep five seconds between each * attempt => 25 seconds before timeout! */ while((failure == 1) && (counter <= 3)) { if (*ldp != NULL) ldap_unbind(*ldp); /* ----------------------------- */ /* -- Connect to LDAP server. -- */ #ifdef LDAP_API_FEATURE_X_OPENLDAP isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_DEBUG(2), "LDAP sdb zone '%s': ldap_initialize(%s)", zone, data->url); /* Connect to LDAP server using URL */ rc = ldap_initialize(ldp, data->url); if (rc != LDAP_SUCCESS) { #else *ldp = ldap_open(data->hostname, data->portno); if (*ldp == NULL) { #endif isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, #ifdef LDAP_API_FEATURE_X_OPENLDAP "LDAP sdb zone '%s': ldapdb_bind(): ldap_initialize() failed. LDAP URL: %s", zone, data->url); #else "LDAP sdb zone '%s': ldapdb_bind(): ldap_open() failed.", zone); #endif /* Failed - wait five seconds, then try again. */ goto try_bind_again; } else
/*% * Unregisters a DLZ driver. This basically just removes the dlz * driver from the list of available drivers in the dlz_implementations list. */ void dns_dlzunregister(dns_dlzimplementation_t **dlzimp) { dns_dlzimplementation_t *dlz_imp; isc_mem_t *mctx; /* Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Unregistering DLZ driver."); /* * Performs checks to make sure data is as we expect it to be. */ REQUIRE(dlzimp != NULL && *dlzimp != NULL); /* * initialize the dlz_implementations list, this is guaranteed * to only really happen once. */ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS); dlz_imp = *dlzimp; /* lock the dlz_implementations list so we can modify it. */ RWLOCK(&dlz_implock, isc_rwlocktype_write); /* remove the dlz_implementation object from the list */ ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link); mctx = dlz_imp->mctx; /* * Return the memory back to the available memory pool and * remove it from the memory context. */ isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t)); isc_mem_detach(&mctx); /* Unlock the dlz_implementations list. */ RWUNLOCK(&dlz_implock, isc_rwlocktype_write); }
static void stub_dlz_destroy(void *driverarg, void *dbdata) { config_data_t *cd; isc_mem_t *mctx; UNUSED(driverarg); cd = (config_data_t *) dbdata; /* * Write debugging message to log */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Unloading DLZ_stub driver."); isc_mem_free(ns_g_mctx, cd->myzone); isc_mem_free(ns_g_mctx, cd->myname); isc_mem_free(ns_g_mctx, cd->myip); mctx = cd->mctx; isc_mem_put(mctx, cd, sizeof(config_data_t)); isc_mem_detach(&mctx); }
/* * Arrange to send as much as we can of "stream" without blocking. * * Requires: * The stream iterator is initialized and points at an RR, * or possibly at the end of the stream (that is, the * _first method of the iterator has been called). */ static void sendstream(xfrout_ctx_t *xfr) { dns_message_t *tcpmsg = NULL; dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ isc_result_t result; isc_region_t used; isc_region_t region; dns_rdataset_t *qrdataset; dns_name_t *msgname = NULL; dns_rdata_t *msgrdata = NULL; dns_rdatalist_t *msgrdl = NULL; dns_rdataset_t *msgrds = NULL; dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; isc_boolean_t is_tcp; int n_rrs; isc_buffer_clear(&xfr->buf); isc_buffer_clear(&xfr->txlenbuf); isc_buffer_clear(&xfr->txbuf); is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); if (!is_tcp) { /* * In the UDP case, we put the response data directly into * the client message. */ msg = xfr->client->message; CHECK(dns_message_reply(msg, ISC_TRUE)); } else { /* * TCP. Build a response dns_message_t, temporarily storing * the raw, uncompressed owner names and RR data contiguously * in xfr->buf. We know that if the uncompressed data fits * in xfr->buf, the compressed data will surely fit in a TCP * message. */ CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &tcpmsg)); msg = tcpmsg; msg->id = xfr->id; msg->rcode = dns_rcode_noerror; msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) msg->flags |= DNS_MESSAGEFLAG_RA; CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); /* * Add a EDNS option to the message? */ if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) { dns_rdataset_t *opt = NULL; CHECK(ns_client_addopt(xfr->client, msg, &opt)); CHECK(dns_message_setopt(msg, opt)); /* * Add to first message only. */ xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID; xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE; } /* * Account for reserved space. */ if (xfr->tsigkey != NULL) INSIST(msg->reserved != 0U); isc_buffer_add(&xfr->buf, msg->reserved); /* * Include a question section in the first message only. * BIND 8.2.1 will not recognize an IXFR if it does not * have a question section. */ if (xfr->nmsg == 0) { dns_name_t *qname = NULL; isc_region_t r; /* * Reserve space for the 12-byte message header * and 4 bytes of question. */ isc_buffer_add(&xfr->buf, 12 + 4); qrdataset = NULL; result = dns_message_gettemprdataset(msg, &qrdataset); if (result != ISC_R_SUCCESS) goto failure; dns_rdataset_makequestion(qrdataset, xfr->client->message->rdclass, xfr->qtype); result = dns_message_gettempname(msg, &qname); if (result != ISC_R_SUCCESS) goto failure; dns_name_init(qname, NULL); isc_buffer_availableregion(&xfr->buf, &r); INSIST(r.length >= xfr->qname->length); r.length = xfr->qname->length; isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, xfr->qname->length); dns_name_fromregion(qname, &r); ISC_LIST_INIT(qname->list); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(msg, qname, DNS_SECTION_QUESTION); } else { /* * Reserve space for the 12-byte message header */ isc_buffer_add(&xfr->buf, 12); msg->tcp_continuation = 1; } } /* * Try to fit in as many RRs as possible, unless "one-answer" * format has been requested. */ for (n_rrs = 0; ; n_rrs++) { dns_name_t *name = NULL; isc_uint32_t ttl; dns_rdata_t *rdata = NULL; unsigned int size; isc_region_t r; msgname = NULL; msgrdata = NULL; msgrdl = NULL; msgrds = NULL; xfr->stream->methods->current(xfr->stream, &name, &ttl, &rdata); size = name->length + 10 + rdata->length; isc_buffer_availableregion(&xfr->buf, &r); if (size >= r.length) { /* * RR would not fit. If there are other RRs in the * buffer, send them now and leave this RR to the * next message. If this RR overflows the buffer * all by itself, fail. * * In theory some RRs might fit in a TCP message * when compressed even if they do not fit when * uncompressed, but surely we don't want * to send such monstrosities to an unsuspecting * slave. */ if (n_rrs == 0) { xfrout_log(xfr, ISC_LOG_WARNING, "RR too large for zone transfer " "(%d bytes)", size); /* XXX DNS_R_RRTOOLARGE? */ result = ISC_R_NOSPACE; goto failure; } break; } if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) log_rr(name, rdata, ttl); /* XXX */ result = dns_message_gettempname(msg, &msgname); if (result != ISC_R_SUCCESS) goto failure; dns_name_init(msgname, NULL); isc_buffer_availableregion(&xfr->buf, &r); INSIST(r.length >= name->length); r.length = name->length; isc_buffer_putmem(&xfr->buf, name->ndata, name->length); dns_name_fromregion(msgname, &r); /* Reserve space for RR header. */ isc_buffer_add(&xfr->buf, 10); result = dns_message_gettemprdata(msg, &msgrdata); if (result != ISC_R_SUCCESS) goto failure; isc_buffer_availableregion(&xfr->buf, &r); r.length = rdata->length; isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); dns_rdata_init(msgrdata); dns_rdata_fromregion(msgrdata, rdata->rdclass, rdata->type, &r); result = dns_message_gettemprdatalist(msg, &msgrdl); if (result != ISC_R_SUCCESS) goto failure; msgrdl->type = rdata->type; msgrdl->rdclass = rdata->rdclass; msgrdl->ttl = ttl; if (rdata->type == dns_rdatatype_sig || rdata->type == dns_rdatatype_rrsig) msgrdl->covers = dns_rdata_covers(rdata); else msgrdl->covers = dns_rdatatype_none; ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); result = dns_message_gettemprdataset(msg, &msgrds); if (result != ISC_R_SUCCESS) goto failure; result = dns_rdatalist_tordataset(msgrdl, msgrds); INSIST(result == ISC_R_SUCCESS); ISC_LIST_APPEND(msgname->list, msgrds, link); dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); msgname = NULL; result = xfr->stream->methods->next(xfr->stream); if (result == ISC_R_NOMORE) { xfr->end_of_stream = ISC_TRUE; break; } CHECK(result); if (! xfr->many_answers) break; /* * At this stage, at least 1 RR has been rendered into * the message. Check if we want to clamp this message * here (TCP only). 20480 was set as an upper limit to * improve message compression. */ if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && is_tcp) break; } if (is_tcp) { CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); dns_compress_setsensitive(&cctx, ISC_TRUE); cleanup_cctx = ISC_TRUE; CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); CHECK(dns_message_renderend(msg)); dns_compress_invalidate(&cctx); cleanup_cctx = ISC_FALSE; isc_buffer_usedregion(&xfr->txbuf, &used); isc_buffer_putuint16(&xfr->txlenbuf, (isc_uint16_t)used.length); region.base = xfr->txlenbuf.base; region.length = 2 + used.length; xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending TCP message of %d bytes", used.length); CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ ®ion, xfr->client->task, xfrout_senddone, xfr)); xfr->sends++; } else { xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); ns_client_send(xfr->client); xfr->stream->methods->pause(xfr->stream); xfrout_ctx_destroy(&xfr); return; } /* Advance lasttsig to be the last TSIG generated */ CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); xfr->nmsg++; failure: if (msgname != NULL) { if (msgrds != NULL) { if (dns_rdataset_isassociated(msgrds)) dns_rdataset_disassociate(msgrds); dns_message_puttemprdataset(msg, &msgrds); } if (msgrdl != NULL) { ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); dns_message_puttemprdatalist(msg, &msgrdl); } if (msgrdata != NULL) dns_message_puttemprdata(msg, &msgrdata); dns_message_puttempname(msg, &msgname); } if (tcpmsg != NULL) dns_message_destroy(&tcpmsg); if (cleanup_cctx) dns_compress_invalidate(&cctx); /* * Make sure to release any locks held by database * iterators before returning from the event handler. */ xfr->stream->methods->pause(xfr->stream); if (result == ISC_R_SUCCESS) return; xfrout_fail(xfr, result, "sending zone data"); }
static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; if (query != COUNTZONE) REQUIRE(*rs == NULL); else REQUIRE(rs == NULL); /* get db instance / connection */ dbi = (dbinstance_t *) dbdata; /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: /* same as comments as ALLNODES */ if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } /* * what type of query are we going to run? this time we build * the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(ns_g_mctx, dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i=0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j=0; mysql_ping((MYSQL *) dbi->dbconn) != 0 && j < 4; j++) ; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else { result = ISC_R_FAILURE; } cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even get DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring); /* return result */ return result; }
isc_result_t ns_controls_configure(ns_controls_t *cp, const cfg_obj_t *config, cfg_aclconfctx_t *aclconfctx) { controllistener_t *listener; controllistenerlist_t new_listeners; const cfg_obj_t *controlslist = NULL; const cfg_listelt_t *element, *element2; char socktext[ISC_SOCKADDR_FORMATSIZE]; ISC_LIST_INIT(new_listeners); /* * Get the list of named.conf 'controls' statements. */ (void)cfg_map_get(config, "controls", &controlslist); /* * Run through the new control channel list, noting sockets that * are already being listened on and moving them to the new list. * * Identifying duplicate addr/port combinations is left to either * the underlying config code, or to the bind attempt getting an * address-in-use error. */ if (controlslist != NULL) { for (element = cfg_list_first(controlslist); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *controls; const cfg_obj_t *inetcontrols = NULL; controls = cfg_listelt_value(element); (void)cfg_map_get(controls, "inet", &inetcontrols); if (inetcontrols == NULL) continue; for (element2 = cfg_list_first(inetcontrols); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *control; const cfg_obj_t *obj; isc_sockaddr_t addr; /* * The parser handles BIND 8 configuration file * syntax, so it allows unix phrases as well * inet phrases with no keys{} clause. */ control = cfg_listelt_value(element2); obj = cfg_tuple_get(control, "address"); addr = *cfg_obj_assockaddr(obj); if (isc_sockaddr_getport(&addr) == 0) isc_sockaddr_setport(&addr, NS_CONTROL_PORT); isc_sockaddr_format(&addr, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_DEBUG(9), "processing control channel %s", socktext); update_listener(cp, &listener, control, config, &addr, aclconfctx, socktext, isc_sockettype_tcp); if (listener != NULL) /* * Remove the listener from the old * list, so it won't be shut down. */ ISC_LIST_UNLINK(cp->listeners, listener, link); else /* * This is a new listener. */ add_listener(cp, &listener, control, config, &addr, aclconfctx, socktext, isc_sockettype_tcp); if (listener != NULL) ISC_LIST_APPEND(new_listeners, listener, link); } } for (element = cfg_list_first(controlslist); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *controls; const cfg_obj_t *unixcontrols = NULL; controls = cfg_listelt_value(element); (void)cfg_map_get(controls, "unix", &unixcontrols); if (unixcontrols == NULL) continue; for (element2 = cfg_list_first(unixcontrols); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *control; const cfg_obj_t *path; isc_sockaddr_t addr; isc_result_t result; /* * The parser handles BIND 8 configuration file * syntax, so it allows unix phrases as well * inet phrases with no keys{} clause. */ control = cfg_listelt_value(element2); path = cfg_tuple_get(control, "path"); result = isc_sockaddr_frompath(&addr, cfg_obj_asstring(path)); if (result != ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_DEBUG(9), "control channel '%s': %s", cfg_obj_asstring(path), isc_result_totext(result)); continue; } isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_DEBUG(9), "processing control channel '%s'", cfg_obj_asstring(path)); update_listener(cp, &listener, control, config, &addr, aclconfctx, cfg_obj_asstring(path), isc_sockettype_unix); if (listener != NULL) /* * Remove the listener from the old * list, so it won't be shut down. */ ISC_LIST_UNLINK(cp->listeners, listener, link); else /* * This is a new listener. */ add_listener(cp, &listener, control, config, &addr, aclconfctx, cfg_obj_asstring(path), isc_sockettype_unix); if (listener != NULL) ISC_LIST_APPEND(new_listeners, listener, link); } } } else { int i; for (i = 0; i < 2; i++) { isc_sockaddr_t addr; if (i == 0) { struct in_addr localhost; if (isc_net_probeipv4() != ISC_R_SUCCESS) continue; localhost.s_addr = htonl(INADDR_LOOPBACK); isc_sockaddr_fromin(&addr, &localhost, 0); } else { if (isc_net_probeipv6() != ISC_R_SUCCESS) continue; isc_sockaddr_fromin6(&addr, &in6addr_loopback, 0); } isc_sockaddr_setport(&addr, NS_CONTROL_PORT); isc_sockaddr_format(&addr, socktext, sizeof(socktext)); update_listener(cp, &listener, NULL, NULL, &addr, NULL, socktext, isc_sockettype_tcp); if (listener != NULL) /* * Remove the listener from the old * list, so it won't be shut down. */ ISC_LIST_UNLINK(cp->listeners, listener, link); else /* * This is a new listener. */ add_listener(cp, &listener, NULL, NULL, &addr, NULL, socktext, isc_sockettype_tcp); if (listener != NULL) ISC_LIST_APPEND(new_listeners, listener, link); } } /* * ns_control_shutdown() will stop whatever is on the global * listeners list, which currently only has whatever sockaddrs * were in the previous configuration (if any) that do not * remain in the current configuration. */ controls_shutdown(cp); /* * Put all of the valid listeners on the listeners list. * Anything already on listeners in the process of shutting * down will be taken care of by listen_done(). */ ISC_LIST_APPENDLIST(cp->listeners, new_listeners, link); return (ISC_R_SUCCESS); }
/*% * This function is the real core of the driver. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds either: * 1) a list of database instances (in multithreaded mode) OR * 2) a single database instance (in single threaded mode) * The function will construct the query and obtain an available * database instance (DBI). It will then run the query and hopefully * obtain a result set. Postgres is nice, in that once the result * set is returned, we can make the db connection available for another * thread to use, while this thread continues on. So, the DBI is made * available ASAP by unlocking the instance_lock after we have cleaned * it up properly. */ static isc_result_t postgres_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, PGresult **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; /* temporarily get a unique thread # */ unsigned int dlz_thread_num = 1+(int) (1000.0*rand()/(RAND_MAX+1.0)); REQUIRE(*rs == NULL); #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d Getting DBI", dlz_thread_num); #endif /* get db instance / connection */ #ifdef ISC_PLATFORM_USETHREADS /* find an available DBI from the list */ dbi = postgres_find_avail_conn((db_list_t *) dbdata); #else /* ISC_PLATFORM_USETHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *) dbdata; #endif /* ISC_PLATFORM_USETHREADS */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d Got DBI - checking query", dlz_thread_num); #endif /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "postgres_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d checked query", dlz_thread_num); #endif /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = postgres_escape_string(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did zone", dlz_thread_num); #endif /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = postgres_escape_string(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did record", dlz_thread_num); #endif /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = postgres_escape_string(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did client", dlz_thread_num); #endif /* * what type of query are we going to run? * this time we build the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "postgres_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d built query", dlz_thread_num); #endif /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d query is '%s'", dlz_thread_num, querystring); #endif /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (j=0; j < 3; j++) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d executing query for %d time", dlz_thread_num, j); #endif /* try to get result set */ *rs = PQexec((PGconn *)dbi->dbconn, querystring ); result = ISC_R_SUCCESS; /* * if result set is null, reset DB connection, max 3 * attempts. */ for (i=0; *rs == NULL && i < 3; i++) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d resetting connection", dlz_thread_num); #endif result = ISC_R_FAILURE; PQreset((PGconn *) dbi->dbconn); /* connection ok, break inner loop */ if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK) break; } /* result set ok, break outter loop */ if (PQresultStatus(*rs) == PGRES_TUPLES_OK) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d rs ok", dlz_thread_num); #endif break; } else { /* we got a result set object, but it's not right. */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d clearing rs", dlz_thread_num); #endif PQclear(*rs); /* get rid of it */ /* in case this was the last attempt */ result = ISC_R_FAILURE; } } cleanup: /* it's always good to cleanup after yourself */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d cleaning up", dlz_thread_num); #endif /* if we couldn't even allocate DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); #ifdef ISC_PLATFORM_USETHREADS #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d unlocking mutex", dlz_thread_num); #endif /* release the lock so another thread can use this dbi */ isc_mutex_unlock(&dbi->instance_lock); #endif /* ISC_PLATFORM_USETHREADS */ /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring ); #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d returning", dlz_thread_num); #endif /* return result */ return result; }
/*% * create an instance of the driver. Remember, only 1 copy of the driver's * code is ever loaded, the driver has to remember which context it's * operating in. This is done via use of the dbdata argument which is * passed into all query functions. */ static isc_result_t postgres_create(const char *dlzname, unsigned int argc, char *argv[], void *driverarg, void **dbdata) { isc_result_t result; dbinstance_t *dbi = NULL; unsigned int j; #ifdef ISC_PLATFORM_USETHREADS /* if multi-threaded, we need a few extra variables. */ int dbcount; db_list_t *dblist = NULL; int i; char *endp; #endif /* ISC_PLATFORM_USETHREADS */ UNUSED(driverarg); UNUSED(dlzname); /* seed random # generator */ srand( (unsigned)time( NULL ) ); #ifdef ISC_PLATFORM_USETHREADS /* if debugging, let user know we are multithreaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Postgres driver running multithreaded"); #else /* ISC_PLATFORM_USETHREADS */ /* if debugging, let user know we are single threaded. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "Postgres driver running single threaded"); #endif /* ISC_PLATFORM_USETHREADS */ /* verify we have at least 5 arg's passed to the driver */ if (argc < 5) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver requires at least " "4 command line args."); return (ISC_R_FAILURE); } /* no more than 8 arg's should be passed to the driver */ if (argc > 8) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver cannot accept more than " "7 command line args."); return (ISC_R_FAILURE); } /* multithreaded build can have multiple DB connections */ #ifdef ISC_PLATFORM_USETHREADS /* check how many db connections we should create */ dbcount = strtol(argv[1], &endp, 10); if (*endp != '\0' || dbcount < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver database connection count " "must be positive."); return (ISC_R_FAILURE); } /* allocate memory for database connection list */ dblist = isc_mem_get(ns_g_mctx, sizeof(db_list_t)); if (dblist == NULL) return (ISC_R_NOMEMORY); /* initialize DB connection list */ ISC_LIST_INIT(*dblist); /* * create the appropriate number of database instances (DBI) * append each new DBI to the end of the list */ for (i=0; i < dbcount; i++) { #endif /* ISC_PLATFORM_USETHREADS */ /* how many queries were passed in from config file? */ switch(argc) { case 5: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[3], argv[4], NULL, &dbi); break; case 6: result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[5], argv[3], argv[4], NULL, &dbi); break; case 7: result = build_sqldbinstance(ns_g_mctx, argv[6], NULL, argv[5], argv[3], argv[4], NULL, &dbi); break; case 8: result = build_sqldbinstance(ns_g_mctx, argv[6], argv[7], argv[5], argv[3], argv[4], NULL, &dbi); break; default: /* not really needed, should shut up compiler. */ result = ISC_R_FAILURE; } if (result == ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "Postgres driver created database " "instance object."); } else { /* unsuccessful?, log err msg and cleanup. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver could not create " "database instance object."); goto cleanup; } #ifdef ISC_PLATFORM_USETHREADS /* when multithreaded, build a list of DBI's */ ISC_LINK_INIT(dbi, link); ISC_LIST_APPEND(*dblist, dbi, link); #endif /* create and set db connection */ dbi->dbconn = PQconnectdb(argv[2]); /* * if db connection cannot be created, log err msg and * cleanup. */ if (dbi->dbconn == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver could not allocate " "memory for database connection"); goto cleanup; } /* if we cannot connect the first time, try 3 more times. */ for (j = 0; PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK && j < 3; j++) PQreset((PGconn *) dbi->dbconn); #ifdef ISC_PLATFORM_USETHREADS /* * if multi threaded, let user know which connection * failed. user could be attempting to create 10 db * connections and for some reason the db backend only * allows 9 */ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver failed to create " "database connection number %u " "after 4 attempts", i + 1); goto cleanup; } /* set DBI = null for next loop through. */ dbi = NULL; } /* end for loop */ /* set dbdata to the list we created. */ *dbdata = dblist; #else /* ISC_PLATFORM_USETHREADS */ /* if single threaded, just let user know we couldn't connect. */ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver failed to create database " "connection after 4 attempts"); goto cleanup; } /* * single threaded build can only use 1 db connection, return * it via dbdata */ *dbdata = dbi; #endif /* ISC_PLATFORM_USETHREADS */ /* hey, we got through all of that ok, return success. */ return(ISC_R_SUCCESS); cleanup: #ifdef ISC_PLATFORM_USETHREADS /* * if multithreaded, we could fail because only 1 connection * couldn't be made. We should cleanup the other successful * connections properly. */ postgres_destroy_dblist(dblist); #else /* ISC_PLATFORM_USETHREADS */ if (dbi != NULL) destroy_sqldbinstance(dbi); #endif /* ISC_PLATFORM_USETHREADS */ return(ISC_R_FAILURE); }
static isc_result_t do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, isc_boolean_t verbose) { isc_interfaceiter_t *iter = NULL; isc_boolean_t scan_ipv4 = ISC_FALSE; isc_boolean_t scan_ipv6 = ISC_FALSE; isc_boolean_t adjusting = ISC_FALSE; isc_boolean_t ipv6only = ISC_TRUE; isc_boolean_t ipv6pktinfo = ISC_TRUE; isc_result_t result; isc_netaddr_t zero_address, zero_address6; ns_listenelt_t *le; isc_sockaddr_t listen_addr; ns_interface_t *ifp; isc_boolean_t log_explicit = ISC_FALSE; isc_boolean_t dolistenon; if (ext_listen != NULL) adjusting = ISC_TRUE; if (isc_net_probeipv6() == ISC_R_SUCCESS) scan_ipv6 = ISC_TRUE; #ifdef WANT_IPV6 else isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv6 interfaces found"); #endif if (isc_net_probeipv4() == ISC_R_SUCCESS) scan_ipv4 = ISC_TRUE; else isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv4 interfaces found"); /* * A special, but typical case; listen-on-v6 { any; }. * When we can make the socket IPv6-only, open a single wildcard * socket for IPv6 communication. Otherwise, make separate socket * for each IPv6 address in order to avoid accepting IPv4 packets * as the form of mapped addresses unintentionally unless explicitly * allowed. */ #ifndef ISC_ALLOW_MAPPED if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6only() != ISC_R_SUCCESS) { ipv6only = ISC_FALSE; log_explicit = ISC_TRUE; } #endif if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) { ipv6pktinfo = ISC_FALSE; log_explicit = ISC_TRUE; } if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) { for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { struct in6_addr in6a; if (!listenon_is_ip6_any(le)) continue; in6a = in6addr_any; isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); ifp = find_matching_interface(mgr, &listen_addr); if (ifp != NULL) { ifp->generation = mgr->generation; } else { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "listening on IPv6 " "interfaces, port %u", le->port); result = ns_interface_setup(mgr, &listen_addr, "<any>", &ifp, ISC_TRUE); if (result == ISC_R_SUCCESS) ifp->flags |= NS_INTERFACEFLAG_ANYADDR; else isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "listening on all IPv6 " "interfaces failed"); /* Continue. */ } } } isc_netaddr_any(&zero_address); isc_netaddr_any6(&zero_address6); result = isc_interfaceiter_create(mgr->mctx, &iter); if (result != ISC_R_SUCCESS) return (result); if (adjusting == ISC_FALSE) { result = clearacl(mgr->mctx, &mgr->aclenv.localhost); if (result != ISC_R_SUCCESS) goto cleanup_iter; result = clearacl(mgr->mctx, &mgr->aclenv.localnets); if (result != ISC_R_SUCCESS) goto cleanup_iter; clearlistenon(mgr); } for (result = isc_interfaceiter_first(iter); result == ISC_R_SUCCESS; result = isc_interfaceiter_next(iter)) { isc_interface_t interface; ns_listenlist_t *ll; unsigned int family; result = isc_interfaceiter_current(iter, &interface); if (result != ISC_R_SUCCESS) break; family = interface.address.family; if (family != AF_INET && family != AF_INET6) continue; if (scan_ipv4 == ISC_FALSE && family == AF_INET) continue; if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; /* * Test for the address being nonzero rather than testing * INTERFACE_F_UP, because on some systems the latter * follows the media state and we could end up ignoring * the interface for an entire rescan interval due to * a temporary media glitch at rescan time. */ if (family == AF_INET && isc_netaddr_equal(&interface.address, &zero_address)) { continue; } if (family == AF_INET6 && isc_netaddr_equal(&interface.address, &zero_address6)) { continue; } if (adjusting == ISC_FALSE) { result = setup_locals(mgr, &interface); if (result != ISC_R_SUCCESS) goto ignore_interface; } ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; dolistenon = ISC_TRUE; for (le = ISC_LIST_HEAD(ll->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { int match; isc_boolean_t ipv6_wildcard = ISC_FALSE; isc_netaddr_t listen_netaddr; isc_sockaddr_t listen_sockaddr; /* * Construct a socket address for this IP/port * combination. */ if (family == AF_INET) { isc_netaddr_fromin(&listen_netaddr, &interface.address.type.in); } else { isc_netaddr_fromin6(&listen_netaddr, &interface.address.type.in6); isc_netaddr_setzone(&listen_netaddr, interface.address.zone); } isc_sockaddr_fromnetaddr(&listen_sockaddr, &listen_netaddr, le->port); /* * See if the address matches the listen-on statement; * if not, ignore the interface. */ (void)dns_acl_match(&listen_netaddr, NULL, le->acl, &mgr->aclenv, &match, NULL); if (match <= 0) continue; if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) { setup_listenon(mgr, &interface, le->port); dolistenon = ISC_FALSE; } /* * The case of "any" IPv6 address will require * special considerations later, so remember it. */ if (family == AF_INET6 && ipv6only && ipv6pktinfo && listenon_is_ip6_any(le)) ipv6_wildcard = ISC_TRUE; /* * When adjusting interfaces with extra a listening * list, see if the address matches the extra list. * If it does, and is also covered by a wildcard * interface, we need to listen on the address * explicitly. */ if (adjusting == ISC_TRUE) { ns_listenelt_t *ele; match = 0; for (ele = ISC_LIST_HEAD(ext_listen->elts); ele != NULL; ele = ISC_LIST_NEXT(ele, link)) { (void)dns_acl_match(&listen_netaddr, NULL, ele->acl, NULL, &match, NULL); if (match > 0 && (ele->port == le->port || ele->port == 0)) break; else match = 0; } if (ipv6_wildcard == ISC_TRUE && match == 0) continue; } ifp = find_matching_interface(mgr, &listen_sockaddr); if (ifp != NULL) { ifp->generation = mgr->generation; } else { char sabuf[ISC_SOCKADDR_FORMATSIZE]; if (adjusting == ISC_FALSE && ipv6_wildcard == ISC_TRUE) continue; if (log_explicit && family == AF_INET6 && !adjusting && listenon_is_ip6_any(le)) { isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "IPv6 socket API is " "incomplete; explicitly " "binding to each IPv6 " "address separately"); log_explicit = ISC_FALSE; } isc_sockaddr_format(&listen_sockaddr, sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "%s" "listening on %s interface " "%s, %s", (adjusting == ISC_TRUE) ? "additionally " : "", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, sabuf); result = ns_interface_setup(mgr, &listen_sockaddr, interface.name, &ifp, (adjusting == ISC_TRUE) ? ISC_FALSE : ISC_TRUE); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating %s interface " "%s failed; interface " "ignored", (family == AF_INET) ? "IPv4" : "IPv6", interface.name); } /* Continue. */ } } continue; ignore_interface: isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "ignoring %s interface %s: %s", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, isc_result_totext(result)); continue; } if (result != ISC_R_NOMORE) UNEXPECTED_ERROR(__FILE__, __LINE__, "interface iteration failed: %s", isc_result_totext(result)); else result = ISC_R_SUCCESS; cleanup_iter: isc_interfaceiter_destroy(&iter); return (result); }
void ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { isc_result_t result; dns_name_t *question_name; dns_rdataset_t *question_rdataset; dns_zone_t *zone = NULL, *raw = NULL, *mayberaw; dns_db_t *db = NULL; dns_dbversion_t *ver = NULL; dns_rdataclass_t question_class; rrstream_t *soa_stream = NULL; rrstream_t *data_stream = NULL; rrstream_t *stream = NULL; dns_difftuple_t *current_soa_tuple = NULL; dns_name_t *soa_name; dns_rdataset_t *soa_rdataset; dns_rdata_t soa_rdata = DNS_RDATA_INIT; isc_boolean_t have_soa = ISC_FALSE; const char *mnemonic = NULL; isc_mem_t *mctx = client->mctx; dns_message_t *request = client->message; xfrout_ctx_t *xfr = NULL; isc_quota_t *quota = NULL; dns_transfer_format_t format = client->view->transfer_format; isc_netaddr_t na; dns_peer_t *peer = NULL; isc_buffer_t *tsigbuf = NULL; char *journalfile; char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; char keyname[DNS_NAME_FORMATSIZE]; isc_boolean_t is_poll = ISC_FALSE; isc_boolean_t is_dlz = ISC_FALSE; isc_boolean_t is_ixfr = ISC_FALSE; isc_uint32_t begin_serial = 0, current_serial; switch (reqtype) { case dns_rdatatype_axfr: mnemonic = "AXFR"; break; case dns_rdatatype_ixfr: mnemonic = "IXFR"; break; default: INSIST(0); break; } ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(6), "%s request", mnemonic); /* * Apply quota. */ result = isc_quota_attach(&ns_g_server->xfroutquota, "a); if (result != ISC_R_SUCCESS) { isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, "%s request denied: %s", mnemonic, isc_result_totext(result)); goto failure; } /* * Interpret the question section. */ result = dns_message_firstname(request, DNS_SECTION_QUESTION); INSIST(result == ISC_R_SUCCESS); /* * The question section must contain exactly one question, and * it must be for AXFR/IXFR as appropriate. */ question_name = NULL; dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); question_rdataset = ISC_LIST_HEAD(question_name->list); question_class = question_rdataset->rdclass; INSIST(question_rdataset->type == reqtype); if (ISC_LIST_NEXT(question_rdataset, link) != NULL) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_message_nextname(request, DNS_SECTION_QUESTION); if (result != ISC_R_NOMORE) FAILC(DNS_R_FORMERR, "multiple questions"); result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, &zone); if (result != ISC_R_SUCCESS) { /* * Normal zone table does not have a match. * Try the DLZ database */ // Temporary: only searching the first DLZ database if (! ISC_LIST_EMPTY(client->view->dlz_searched)) { result = dns_dlzallowzonexfr(client->view, question_name, &client->peeraddr, &db); pfilter_notify(result, client, "zonexfr"); if (result == ISC_R_NOPERM) { char _buf1[DNS_NAME_FORMATSIZE]; char _buf2[DNS_RDATACLASS_FORMATSIZE]; result = DNS_R_REFUSED; dns_name_format(question_name, _buf1, sizeof(_buf1)); dns_rdataclass_format(question_class, _buf2, sizeof(_buf2)); ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_XFER_OUT, ISC_LOG_ERROR, "zone transfer '%s/%s' denied", _buf1, _buf2); goto failure; } if (result != ISC_R_SUCCESS) FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); is_dlz = ISC_TRUE; } else { /* * not DLZ and not in normal zone table, we are * not authoritative */ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } } else { /* zone table has a match */ switch(dns_zone_gettype(zone)) { /* Master and slave zones are OK for transfer. */ case dns_zone_master: case dns_zone_slave: case dns_zone_dlz: break; default: FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); } CHECK(dns_zone_getdb(zone, &db)); dns_db_currentversion(db, &ver); } xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s question section OK", mnemonic); /* * Check the authority section. Look for a SOA record with * the same name and class as the question. */ for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) { soa_name = NULL; dns_message_currentname(request, DNS_SECTION_AUTHORITY, &soa_name); /* * Ignore data whose owner name is not the zone apex. */ if (! dns_name_equal(soa_name, question_name)) continue; for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); soa_rdataset != NULL; soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) { /* * Ignore non-SOA data. */ if (soa_rdataset->type != dns_rdatatype_soa) continue; if (soa_rdataset->rdclass != question_class) continue; CHECK(dns_rdataset_first(soa_rdataset)); dns_rdataset_current(soa_rdataset, &soa_rdata); result = dns_rdataset_next(soa_rdataset); if (result == ISC_R_SUCCESS) FAILC(DNS_R_FORMERR, "IXFR authority section " "has multiple SOAs"); have_soa = ISC_TRUE; goto got_soa; } } got_soa: if (result != ISC_R_NOMORE) CHECK(result); xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), "%s authority section OK", mnemonic); /* * If not a DLZ zone, decide whether to allow this transfer. */ if (!is_dlz) { ns_client_aclmsg("zone transfer", question_name, reqtype, client->view->rdclass, msg, sizeof(msg)); CHECK(ns_client_checkacl(client, NULL, msg, dns_zone_getxfracl(zone), ISC_TRUE, ISC_LOG_ERROR)); } /* * AXFR over UDP is not possible. */ if (reqtype == dns_rdatatype_axfr && (client->attributes & NS_CLIENTATTR_TCP) == 0) FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); /* * Look up the requesting server in the peer table. */ isc_netaddr_fromsockaddr(&na, &client->peeraddr); (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); /* * Decide on the transfer format (one-answer or many-answers). */ if (peer != NULL) (void)dns_peer_gettransferformat(peer, &format); /* * Get a dynamically allocated copy of the current SOA. */ if (is_dlz) dns_db_currentversion(db, &ver); CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, ¤t_soa_tuple)); current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); if (reqtype == dns_rdatatype_ixfr) { isc_boolean_t provide_ixfr; /* * Outgoing IXFR may have been disabled for this peer * or globally. */ provide_ixfr = client->view->provideixfr; if (peer != NULL) (void) dns_peer_getprovideixfr(peer, &provide_ixfr); if (provide_ixfr == ISC_FALSE) goto axfr_fallback; if (! have_soa) FAILC(DNS_R_FORMERR, "IXFR request missing SOA"); begin_serial = dns_soa_getserial(&soa_rdata); /* * RFC1995 says "If an IXFR query with the same or * newer version number than that of the server * is received, it is replied to with a single SOA * record of the server's current version, just as * in AXFR". The claim about AXFR is incorrect, * but other than that, we do as the RFC says. * * Sending a single SOA record is also how we refuse * IXFR over UDP (currently, we always do). */ if (DNS_SERIAL_GE(begin_serial, current_serial) || (client->attributes & NS_CLIENTATTR_TCP) == 0) { CHECK(soa_rrstream_create(mctx, db, ver, &stream)); is_poll = ISC_TRUE; goto have_stream; } journalfile = is_dlz ? NULL : dns_zone_getjournal(zone); if (journalfile != NULL) result = ixfr_rrstream_create(mctx, journalfile, begin_serial, current_serial, &data_stream); else result = ISC_R_NOTFOUND; if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(4), "IXFR version not in journal, " "falling back to AXFR"); mnemonic = "AXFR-style IXFR"; goto axfr_fallback; } CHECK(result); is_ixfr = ISC_TRUE; } else { axfr_fallback: CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream)); } /* * Bracket the data stream with SOAs. */ CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, &stream)); soa_stream = NULL; data_stream = NULL; have_stream: CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); /* * Create the xfrout context object. This transfers the ownership * of "stream", "db", "ver", and "quota" to the xfrout context object. */ if (is_dlz) CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, 3600, 3600, (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); else CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, reqtype, question_class, zone, db, ver, quota, stream, dns_message_gettsigkey(request), tsigbuf, dns_zone_getmaxxfrout(zone), dns_zone_getidleout(zone), (format == dns_many_answers) ? ISC_TRUE : ISC_FALSE, &xfr)); xfr->mnemonic = mnemonic; stream = NULL; quota = NULL; CHECK(xfr->stream->methods->first(xfr->stream)); if (xfr->tsigkey != NULL) dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); else keyname[0] = '\0'; if (is_poll) xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); else if (is_ixfr) xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname, begin_serial, current_serial); else xfrout_log1(client, question_name, question_class, ISC_LOG_INFO, "%s started%s%s (serial %u)", mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname, current_serial); if (zone != NULL) { dns_zone_getraw(zone, &raw); mayberaw = (raw != NULL) ? raw : zone; if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 && dns_zone_gettype(mayberaw) == dns_zone_slave) { isc_time_t expiretime; isc_uint32_t secs; dns_zone_getexpiretime(zone, &expiretime); secs = isc_time_seconds(&expiretime); if (secs >= client->now && result == ISC_R_SUCCESS) { client->attributes |= NS_CLIENTATTR_HAVEEXPIRE; client->expire = secs - client->now; } } if (raw != NULL) dns_zone_detach(&raw); } /* * Hand the context over to sendstream(). Set xfr to NULL; * sendstream() is responsible for either passing the * context on to a later event handler or destroying it. */ sendstream(xfr); xfr = NULL; result = ISC_R_SUCCESS; failure: if (result == DNS_R_REFUSED) inc_stats(zone, dns_nsstatscounter_xfrrej); if (quota != NULL) isc_quota_detach("a); if (current_soa_tuple != NULL) dns_difftuple_free(¤t_soa_tuple); if (stream != NULL) stream->methods->destroy(&stream); if (soa_stream != NULL) soa_stream->methods->destroy(&soa_stream); if (data_stream != NULL) data_stream->methods->destroy(&data_stream); if (ver != NULL) dns_db_closeversion(db, &ver, ISC_FALSE); if (db != NULL) dns_db_detach(&db); if (zone != NULL) dns_zone_detach(&zone); /* XXX kludge */ if (xfr != NULL) { xfrout_fail(xfr, result, "setting up zone transfer"); } else if (result != ISC_R_SUCCESS) { ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3), "zone transfer setup failed"); ns_client_error(client, result); } }