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 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { va_list ap; char message[4096]; char namestr[DNS_NAME_FORMATSIZE]; char creatorstr[DNS_NAME_FORMATSIZE]; if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; if (key != NULL) dns_name_format(&key->name, namestr, sizeof(namestr)); else strcpy(namestr, "<null>"); if (key != NULL && key->generated && key->creator) dns_name_format(key->creator, creatorstr, sizeof(creatorstr)); else strcpy(creatorstr, "<null>"); va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); if (key != NULL && key->generated) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, level, "tsig key '%s' (%s): %s", namestr, creatorstr, message); else isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, level, "tsig key '%s': %s", namestr, message); }
/* * Get a modulus for a hash function that is tolerably likely to be * relatively prime to most inputs. Of course, we get a prime for for initial * values not larger than the square of the last prime. We often get a prime * after that. * This works well in practice for hash tables up to at least 100 * times the square of the last prime and better than a multiplicative hash. */ static int hash_divisor(unsigned int initial) { static isc_uint16_t primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, #if 0 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,1009, #endif }; int divisions, tries; unsigned int result; isc_uint16_t *pp, p; result = initial; if (primes[sizeof(primes)/sizeof(primes[0])-1] >= result) { pp = primes; while (*pp < result) ++pp; return (*pp); } if ((result & 1) == 0) ++result; divisions = 0; tries = 1; pp = primes; do { p = *pp++; ++divisions; if ((result % p) == 0) { ++tries; result += 2; pp = primes; } } while (pp < &primes[sizeof(primes) / sizeof(primes[0])]); if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3, "%d hash_divisor() divisions in %d tries" " to get %d from %d", divisions, tries, result, initial); return (result); }
static void badname(int level, dns_name_t *name, const char *comment) { char printname[DNS_NAME_FORMATSIZE]; if (isc_log_wouldlog(dns_lctx, level)) { dns_name_format(name, printname, sizeof(printname)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_RBTDB, level, "invalid response policy name \"%s\"%s", printname, comment); } }
static void badname(int level, dns_name_t *name, const char *str1, const char *str2) { char printname[DNS_NAME_FORMATSIZE]; if (level < DNS_RPZ_DEBUG_QUIET && isc_log_wouldlog(dns_lctx, level)) { dns_name_format(name, printname, sizeof(printname)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB, level, "invalid rpz IP address \"%s\"%s%s", printname, str1, str2); } }
static void delv_log(int level, const char *fmt, ...) { va_list ap; char msgbuf[2048]; if (! isc_log_wouldlog(lctx, level)) return; va_start(ap, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); isc_log_write(lctx, LOGCATEGORY_DEFAULT, LOGMODULE_DEFAULT, level, "%s", msgbuf); va_end(ap); }
static void log_dampening(const dns_dampening_t * conf, const isc_netaddr_t * prefix, int enabled) { char pb[ISC_NETADDR_FORMATSIZE]; int len; INSIST(conf != NULL); INSIST(prefix != NULL); switch(prefix->family) { case AF_INET : len = conf->prefixlen.ipv4; break; case AF_INET6: len = conf->prefixlen.ipv6; break; default : return; } if(isc_log_wouldlog(dns_lctx, ISC_LOG_INFO)) { isc_netaddr_format(prefix, pb, sizeof(pb)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DAMPENING, DNS_LOGMODULE_REQUEST, ISC_LOG_INFO, "%s/%d dampening %s.",pb, len, enabled ? "activated" : "removed"); } }
/* * 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"); }
dns_dampening_state_t dns_dampening_query(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, int * penalty) { isc_netaddr_t netaddr, prefix; dns_dampening_state_t final_state = DNS_DAMPENING_STATE_NORMAL, state = DNS_DAMPENING_STATE_NORMAL; dns_dampening_entry_t * entry; dns_dampening_implementation_t *impl; int max_penalty = -2; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { max_penalty = ISC_MAX(max_penalty, -1); DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); if(damp->statistics.report_interval > 0 && damp->statistics.report_interval + impl->statistics.last_report <= now) { if(isc_log_wouldlog(dns_lctx, ISC_LOG_INFO)) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DAMPENING, DNS_LOGMODULE_REQUEST, ISC_LOG_INFO, "Stats for #%d: queries %u/%u/%u: lock=%ld.%06ld, search=%ld.%06ld, update=%ld.%06ld, add=%ld.%06ld", impl - damp->workers, impl->statistics.allowed, impl->statistics.denied, impl->statistics.skipped, impl->statistics.lock.tv_sec, impl->statistics.lock.tv_usec, impl->statistics.search.tv_sec, impl->statistics.search.tv_usec, impl->statistics.update.tv_sec, impl->statistics.update.tv_usec, impl->statistics.add.tv_sec, impl->statistics.add.tv_usec); memset(&impl->statistics, 0, sizeof(impl->statistics)); impl->statistics.last_report = now; } DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry == NULL) { state = DNS_DAMPENING_STATE_NORMAL; DAMPENING_STATISTICS_DO(impl, add, impl->add(impl->data, &prefix, damp->score.first_query, now)); max_penalty = ISC_MAX(max_penalty, 0); } else { state = entry->dampening == 1 ? DNS_DAMPENING_STATE_SUPPRESS : DNS_DAMPENING_STATE_NORMAL; max_penalty = ISC_MAX(max_penalty, entry->penalty); DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, damp->score.per_query, now)); } if(state == DNS_DAMPENING_STATE_NORMAL) { DAMPENING_STATISTICS_INC(impl, allowed); } else { DAMPENING_STATISTICS_INC(impl, denied); final_state = state; /* any dampening suffice */ } UNLOCK(&impl->lock); } if(penalty != NULL) *penalty = max_penalty; return final_state; }