diff --git a/CHANGES b/CHANGES index 4e17e0333e..6e122d2d1d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,36 @@ +3937. [func] Added some debug logging to better indicate the + conditions causing SERVFAILs when resolving. + [RT #35538] + +3936. [func] Added authoritative support for the EDNS Client + Subnet (ECS) option. + + ACLs can now include "ecs" elements which specify + an address or network prefix; if an ECS option is + included in a DNS query, then the address encoded + in the option will be matched against "ecs" ACL + elements. + + Also, if an ECS address is included in a query, + then it will be used instead of the client source + address when matching "geoip" ACL elements. This + behavior can be overridden with "geoip-use-ecs no;". + + When "ecs" or "geoip" ACL elements are used to + select a view for a query, the response will include + an ECS option to indicate which client network the + answer is valid for. + + (Thanks to Vincent Bernat.) [RT #36781] + +3935. [bug] "geoip asnum" ACL elements would not match unless + the full organization name was specified. They + can now match against the AS number alone (e.g., + AS1234). [RT #36945] + +3934. [bug] Catch bad 'sit-secret' in named-checkconf. Improve + sit-secret documentation. [RT #36980] + 3933. [bug] Corrected the implementation of dns_rdata_casecompare() for the HIP rdata type. [RT #36911] diff --git a/README b/README index 8298ae1f88..23ef8a8328 100644 --- a/README +++ b/README @@ -56,6 +56,12 @@ BIND 9.11.0 BIND 9.11.0 includes a number of changes from BIND 9.10 and earlier releases. New features include: + - The EDNS Client Subnet (ECS) option is now supported for + authoritative servers; if a query contains an ECS option + then ACLs containing "geoip" or "ecs" elements can match + against the the address encoded in the option. This can be + used to select a view for a query, so that different answers + can be provided depending on the client network. - The EDNS EXPIRE option has been implemented on the client side, allowing a slave server to set the expiration timer correctly when transferring zone data from another slave diff --git a/bin/named/client.c b/bin/named/client.c index 68d14a942d..f2fe82fa78 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -122,6 +122,7 @@ #endif #define SIT_SIZE 24U /* 8 + 4 + 4 + 8 */ +#define ECS_SIZE 20U /* 2 + 1 + 1 + [0..16] */ /*% nameserver client manager structure */ struct ns_clientmgr { @@ -244,7 +245,8 @@ static void ns_client_dumpmessage(ns_client_t *client, const char *reason); static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, dns_dispatch_t *disp, isc_boolean_t tcp); static inline isc_boolean_t -allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl); +allowed(isc_netaddr_t *addr, dns_name_t *signer, isc_netaddr_t *ecs_addr, + isc_uint8_t ecs_addrlen, isc_uint8_t *ecs_scope, dns_acl_t *acl); #ifdef ISC_PLATFORM_USESIT static void compute_sit(ns_client_t *client, isc_uint32_t when, isc_uint32_t nonce, isc_buffer_t *buf); @@ -1042,7 +1044,8 @@ client_send(ns_client_t *client) { if (client->message->tsigkey != NULL) name = &client->message->tsigkey->name; if (client->view->nocasecompress == NULL || - !allowed(&netaddr, name, client->view->nocasecompress)) + !allowed(&netaddr, name, NULL, 0, NULL, + client->view->nocasecompress)) { dns_compress_setsensitive(&cctx, ISC_TRUE); } @@ -1381,6 +1384,7 @@ isc_result_t ns_client_addopt(ns_client_t *client, dns_message_t *message, dns_rdataset_t **opt) { + unsigned char ecs[ECS_SIZE]; char nsid[BUFSIZ], *nsidp; #ifdef ISC_PLATFORM_USESIT unsigned char sit[SIT_SIZE]; @@ -1459,6 +1463,38 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, ednsopts[count].value = expire; count++; } + if (((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) && + (client->ecs_addr.family == AF_INET || + client->ecs_addr.family == AF_INET6)) + { + int i, addrbytes = (client->ecs_addrlen + 7) / 8; + isc_uint8_t *paddr; + isc_buffer_t buf; + + /* Add client subnet option. */ + isc_buffer_init(&buf, ecs, sizeof(ecs)); + if (client->ecs_addr.family == AF_INET) + isc_buffer_putuint16(&buf, 1); + else + isc_buffer_putuint16(&buf, 2); + isc_buffer_putuint8(&buf, client->ecs_addrlen); + isc_buffer_putuint8(&buf, client->ecs_scope); + + paddr = (isc_uint8_t *) &client->ecs_addr.type; + for (i = 0; i < addrbytes; i++) { + unsigned char uc; + uc = paddr[i]; + if (i == addrbytes - 1 && + ((client->ecs_addrlen % 8) != 0)) + uc &= (1U << (8 - (client->ecs_addrlen % 8))); + isc_buffer_putuint8(&buf, uc); + } + + ednsopts[count].code = DNS_OPT_CLIENT_SUBNET; + ednsopts[count].length = addrbytes + 4; + ednsopts[count].value = ecs; + count++; + } result = dns_message_buildopt(message, opt, 0, udpsize, flags, ednsopts, count); @@ -1466,14 +1502,17 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, } static inline isc_boolean_t -allowed(isc_netaddr_t *addr, dns_name_t *signer, dns_acl_t *acl) { +allowed(isc_netaddr_t *addr, dns_name_t *signer, + isc_netaddr_t *ecs_addr, isc_uint8_t ecs_addrlen, + isc_uint8_t *ecs_scope, dns_acl_t *acl) +{ int match; isc_result_t result; if (acl == NULL) return (ISC_TRUE); - result = dns_acl_match(addr, signer, acl, &ns_g_server->aclenv, - &match, NULL); + result = dns_acl_match2(addr, signer, ecs_addr, ecs_addrlen, ecs_scope, + acl, &ns_g_server->aclenv, &match, NULL); if (result == ISC_R_SUCCESS && match > 0) return (ISC_TRUE); return (ISC_FALSE); @@ -1536,8 +1575,10 @@ ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey, tsig = dns_tsigkey_identity(mykey); } - if (allowed(&netsrc, tsig, view->matchclients) && - allowed(&netdst, tsig, view->matchdestinations)) + if (allowed(&netsrc, tsig, NULL, 0, NULL, + view->matchclients) && + allowed(&netdst, tsig, NULL, 0, NULL, + view->matchdestinations)) break; } return (ISC_TF(view == myview)); @@ -1718,6 +1759,81 @@ process_sit(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { } #endif +static isc_result_t +process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) { + isc_uint16_t family; + isc_uint8_t addrlen, addrbytes, scope, *paddr; + isc_netaddr_t caddr; + int i; + + if (optlen < 4) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "EDNS client subnet option too short"); + return (DNS_R_FORMERR); + } + + family = isc_buffer_getuint16(buf); + addrlen = isc_buffer_getuint8(buf); + scope = isc_buffer_getuint8(buf); + optlen -= 4; + + if (scope != 0U) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "EDNS client subnet option: invalid scope"); + return (DNS_R_FORMERR); + } + + memset(&caddr, 0, sizeof(caddr)); + switch (family) { + case 1: + if (addrlen > 32U) + goto invalid_length; + caddr.family = AF_INET; + break; + case 2: + if (addrlen > 128U) { + invalid_length: + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "EDNS client subnet option: invalid " + "address length (%u) for %s", + addrlen, family == 1 ? "IPv4" : "IPv6"); + return (DNS_R_FORMERR); + } + caddr.family = AF_INET6; + break; + default: + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "EDNS client subnet option: invalid family"); + return (DNS_R_FORMERR); + } + + addrbytes = (addrlen + 7) / 8; + if (isc_buffer_remaininglength(buf) < addrbytes) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), + "EDNS client subnet option: address too short"); + return (DNS_R_FORMERR); + } + + paddr = (isc_uint8_t *) &caddr.type; + for (i = 0; i < addrbytes; i++) { + paddr[i] = isc_buffer_getuint8(buf); + optlen--; + } + + memmove(&client->ecs_addr, &caddr, sizeof(caddr)); + client->ecs_addrlen = addrlen; + client->ecs_scope = 0; + client->attributes |= NS_CLIENTATTR_HAVEECS; + + isc_buffer_forward(buf, optlen); + return (ISC_R_SUCCESS); +} + static isc_result_t process_opt(ns_client_t *client, dns_rdataset_t *opt) { dns_rdata_t rdata; @@ -1788,6 +1904,15 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { client->attributes |= NS_CLIENTATTR_WANTEXPIRE; isc_buffer_forward(&optbuf, optlen); break; + case DNS_OPT_CLIENT_SUBNET: + result = process_ecs(client, &optbuf, optlen); + if (result != ISC_R_SUCCESS) { + ns_client_error(client, result); + goto cleanup; + } + isc_stats_increment(ns_g_server->nsstats, + dns_nsstatscounter_ecsopt); + break; default: isc_stats_increment(ns_g_server->nsstats, dns_nsstatscounter_otheropt); @@ -1925,7 +2050,6 @@ client_request(isc_task_t *task, isc_event_t *event) { * client_newconn. */ if (!TCP_CLIENT(client)) { - if (ns_g_server->blackholeacl != NULL && dns_acl_match(&netaddr, NULL, ns_g_server->blackholeacl, &ns_g_server->aclenv, @@ -2033,6 +2157,10 @@ client_request(isc_task_t *task, isc_event_t *event) { opt = NULL; else opt = dns_message_getopt(client->message); + + client->ecs_addrlen = 0; + client->ecs_scope = 0; + if (opt != NULL) { /* * Are we dropping all EDNS queries? @@ -2117,17 +2245,29 @@ client_request(isc_task_t *task, isc_event_t *event) { client->message->rdclass == dns_rdataclass_any) { dns_name_t *tsig = NULL; + isc_netaddr_t *addr = NULL; + isc_uint8_t *scope = NULL; sigresult = dns_message_rechecksig(client->message, view); - if (sigresult == ISC_R_SUCCESS) - tsig = dns_tsigkey_identity(client->message->tsigkey); + if (sigresult == ISC_R_SUCCESS) { + dns_tsigkey_t *tsigkey; - if (allowed(&netaddr, tsig, view->matchclients) && - allowed(&client->destaddr, tsig, - view->matchdestinations) && - !((client->message->flags & DNS_MESSAGEFLAG_RD) - == 0 && view->matchrecursiveonly)) + tsigkey = client->message->tsigkey; + tsig = dns_tsigkey_identity(tsigkey); + } + + if ((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) { + addr = &client->ecs_addr; + scope = &client->ecs_scope; + } + + if (allowed(&netaddr, tsig, addr, client->ecs_addrlen, + scope, view->matchclients) && + allowed(&client->destaddr, tsig, NULL, + 0, NULL, view->matchdestinations) && + !(view->matchrecursiveonly && + (client->message->flags & DNS_MESSAGEFLAG_RD) == 0)) { dns_view_attach(view, &client->view); break; @@ -2519,6 +2659,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { client->recursionquota = NULL; client->interface = NULL; client->peeraddr_valid = ISC_FALSE; + client->ecs_addrlen = 0; + client->ecs_scope = 0; #ifdef ALLOW_FILTER_AAAA client->filter_aaaa = dns_aaaa_ok; #endif @@ -3055,6 +3197,8 @@ ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, { isc_result_t result; isc_netaddr_t tmpnetaddr; + isc_netaddr_t *ecs_addr = NULL; + isc_uint8_t ecs_addrlen = 0; int match; if (acl == NULL) { @@ -3069,11 +3213,18 @@ ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, netaddr = &tmpnetaddr; } - result = dns_acl_match(netaddr, client->signer, acl, - &ns_g_server->aclenv, &match, NULL); + if ((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) { + ecs_addr = &client->ecs_addr; + ecs_addrlen = client->ecs_addrlen; + } + + result = dns_acl_match2(netaddr, client->signer, + ecs_addr, ecs_addrlen, NULL, acl, + &ns_g_server->aclenv, &match, NULL); if (result != ISC_R_SUCCESS) goto deny; /* Internal error, already logged. */ + if (match > 0) goto allow; goto deny; /* Negative match or no match. */ diff --git a/bin/named/config.c b/bin/named/config.c index f7647e76f7..dfd2852fd8 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -177,6 +177,11 @@ options {\n\ nsec3-test-zone no;\n\ allow-new-zones no;\n\ " +#ifdef HAVE_GEOIP +"\ + geoip-use-ecs yes;\n\ +" +#endif #ifdef ALLOW_FILTER_AAAA " filter-aaaa-on-v4 no;\n\ filter-aaaa-on-v6 no;\n\ diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index c0c3171dc3..48ee578c88 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -137,9 +137,15 @@ struct ns_client { isc_quota_t *tcpquota; isc_quota_t *recursionquota; ns_interface_t *interface; + isc_sockaddr_t peeraddr; isc_boolean_t peeraddr_valid; isc_netaddr_t destaddr; + + isc_netaddr_t ecs_addr; /*%< EDNS client subnet */ + isc_uint8_t ecs_addrlen; + isc_uint8_t ecs_scope; + struct in6_pktinfo pktinfo; isc_dscp_t dscp; isc_event_t ctlevent; @@ -187,6 +193,7 @@ typedef ISC_LIST(ns_client_t) client_list_t; #define NS_CLIENTATTR_WANTEXPIRE 0x0800 /*%< return seconds to expire */ #define NS_CLIENTATTR_HAVEEXPIRE 0x1000 /*%< return seconds to expire */ #define NS_CLIENTATTR_WANTOPT 0x2000 /*%< add opt to reply */ +#define NS_CLIENTATTR_HAVEECS 0x4000 /*%< sent an ECS option */ extern unsigned int ns_client_requests; diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index e1d1db275b..0b241b7471 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -182,18 +182,19 @@ enum { dns_nsstatscounter_nsidopt = 43, dns_nsstatscounter_expireopt = 44, dns_nsstatscounter_otheropt = 45, + dns_nsstatscounter_ecsopt = 46, #ifdef ISC_PLATFORM_USESIT - dns_nsstatscounter_sitopt = 46, - dns_nsstatscounter_sitbadsize = 47, - dns_nsstatscounter_sitbadtime = 48, - dns_nsstatscounter_sitnomatch = 49, - dns_nsstatscounter_sitmatch = 50, - dns_nsstatscounter_sitnew = 51, + dns_nsstatscounter_sitopt = 47, + dns_nsstatscounter_sitbadsize = 48, + dns_nsstatscounter_sitbadtime = 49, + dns_nsstatscounter_sitnomatch = 50, + dns_nsstatscounter_sitmatch = 51, + dns_nsstatscounter_sitnew = 52, - dns_nsstatscounter_max = 52 + dns_nsstatscounter_max = 53 #else - dns_nsstatscounter_max = 46 + dns_nsstatscounter_max = 47 #endif }; diff --git a/bin/named/query.c b/bin/named/query.c index a79a930fd3..babccd0071 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -125,21 +126,25 @@ DNS_RDATASETATTR_NOQNAME) != 0) #if 0 -#define CTRACE(m) isc_log_write(ns_g_lctx, \ - NS_LOGCATEGORY_CLIENT, \ - NS_LOGMODULE_QUERY, \ - ISC_LOG_DEBUG(3), \ - "client %p: %s", client, (m)) -#define QTRACE(m) isc_log_write(ns_g_lctx, \ - NS_LOGCATEGORY_GENERAL, \ - NS_LOGMODULE_QUERY, \ - ISC_LOG_DEBUG(3), \ - "query %p: %s", query, (m)) +#define CTRACE(l,m) do { \ + if (client != NULL && client->query.qname != NULL) { \ + char qbuf[DNS_NAME_FORMATSIZE]; \ + dns_name_format(client->query.qname, qbuf, sizeof(qbuf)); \ + isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, \ + l, "client %p (%s): %s", client, qbuf, (m)); \ + } else { \ + isc_log_write(ns_g_lctx, \ + NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, \ + l, "client %p (): %s", \ + client, (m)); \ + } \ +} while(0) #else -#define CTRACE(m) ((void)m) -#define QTRACE(m) ((void)m) +#define CTRACE(l,m) ((void)m) #endif + #define DNS_GETDB_NOEXACT 0x01U #define DNS_GETDB_NOLOG 0x02U #define DNS_GETDB_PARTIAL 0x04U @@ -312,13 +317,13 @@ static inline void query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { dns_rdataset_t *rdataset = *rdatasetp; - CTRACE("query_putrdataset"); + CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset"); if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); dns_message_puttemprdataset(client->message, rdatasetp); } - CTRACE("query_putrdataset: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset: done"); } static inline void @@ -425,7 +430,7 @@ query_newnamebuf(ns_client_t *client) { isc_buffer_t *dbuf; isc_result_t result; - CTRACE("query_newnamebuf"); + CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf"); /*% * Allocate a name buffer. */ @@ -433,12 +438,13 @@ query_newnamebuf(ns_client_t *client) { dbuf = NULL; result = isc_buffer_allocate(client->mctx, &dbuf, 1024); if (result != ISC_R_SUCCESS) { - CTRACE("query_newnamebuf: isc_buffer_allocate failed: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_newnamebuf: isc_buffer_allocate failed: done"); return (result); } ISC_LIST_APPEND(client->query.namebufs, dbuf, link); - CTRACE("query_newnamebuf: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf: done"); return (ISC_R_SUCCESS); } @@ -448,7 +454,7 @@ query_getnamebuf(ns_client_t *client) { isc_result_t result; isc_region_t r; - CTRACE("query_getnamebuf"); + CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf"); /*% * Return a name buffer with space for a maximal name, allocating * a new one if necessary. @@ -457,7 +463,8 @@ query_getnamebuf(ns_client_t *client) { if (ISC_LIST_EMPTY(client->query.namebufs)) { result = query_newnamebuf(client); if (result != ISC_R_SUCCESS) { - CTRACE("query_getnamebuf: query_newnamebuf failed: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_getnamebuf: query_newnamebuf failed: done"); return (NULL); } } @@ -468,7 +475,8 @@ query_getnamebuf(ns_client_t *client) { if (r.length < 255) { result = query_newnamebuf(client); if (result != ISC_R_SUCCESS) { - CTRACE("query_getnamebuf: query_newnamebuf failed: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_getnamebuf: query_newnamebuf failed: done"); return (NULL); } @@ -476,7 +484,7 @@ query_getnamebuf(ns_client_t *client) { isc_buffer_availableregion(dbuf, &r); INSIST(r.length >= 255); } - CTRACE("query_getnamebuf: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf: done"); return (dbuf); } @@ -484,7 +492,7 @@ static inline void query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { isc_region_t r; - CTRACE("query_keepname"); + CTRACE(ISC_LOG_DEBUG(3), "query_keepname"); /*% * 'name' is using space in 'dbuf', but 'dbuf' has not yet been * adjusted to take account of that. We do the adjustment. @@ -508,14 +516,14 @@ query_releasename(ns_client_t *client, dns_name_t **namep) { * rights on the buffer. */ - CTRACE("query_releasename"); + CTRACE(ISC_LOG_DEBUG(3), "query_releasename"); if (dns_name_hasbuffer(name)) { INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; } dns_message_puttempname(client->message, namep); - CTRACE("query_releasename: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_releasename: done"); } static inline dns_name_t * @@ -528,11 +536,12 @@ query_newname(ns_client_t *client, isc_buffer_t *dbuf, REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); - CTRACE("query_newname"); + CTRACE(ISC_LOG_DEBUG(3), "query_newname"); name = NULL; result = dns_message_gettempname(client->message, &name); if (result != ISC_R_SUCCESS) { - CTRACE("query_newname: dns_message_gettempname failed: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_newname: dns_message_gettempname failed: done"); return (NULL); } isc_buffer_availableregion(dbuf, &r); @@ -541,7 +550,7 @@ query_newname(ns_client_t *client, isc_buffer_t *dbuf, dns_name_setbuffer(name, nbuf); client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; - CTRACE("query_newname: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_newname: done"); return (name); } @@ -550,17 +559,18 @@ query_newrdataset(ns_client_t *client) { dns_rdataset_t *rdataset; isc_result_t result; - CTRACE("query_newrdataset"); + CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset"); rdataset = NULL; result = dns_message_gettemprdataset(client->message, &rdataset); if (result != ISC_R_SUCCESS) { - CTRACE("query_newrdataset: " + CTRACE(ISC_LOG_DEBUG(3), + "query_newrdataset: " "dns_message_gettemprdataset failed: done"); return (NULL); } dns_rdataset_init(rdataset); - CTRACE("query_newrdataset: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: done"); return (rdataset); } @@ -727,8 +737,10 @@ query_validatezonedb(ns_client_t *client, dns_name_t *name, * Get the current version of this database. */ dbversion = query_findversion(client, db); - if (dbversion == NULL) + if (dbversion == NULL) { + CTRACE(ISC_LOG_ERROR, "unable to get db version"); return (DNS_R_SERVFAIL); + } if ((options & DNS_GETDB_IGNOREACL) != 0) goto approved; @@ -1191,7 +1203,7 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, dns_name_t *mname = NULL; isc_result_t result; - CTRACE("query_isduplicate"); + CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate"); for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL; @@ -1202,7 +1214,8 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, /* * We've already got this RRset in the response. */ - CTRACE("query_isduplicate: true: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_isduplicate: true: done"); return (ISC_TRUE); } else if (result == DNS_R_NXRRSET) { /* @@ -1218,7 +1231,7 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, if (mnamep != NULL) *mnamep = mname; - CTRACE("query_isduplicate: false: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done"); return (ISC_FALSE); } @@ -1245,7 +1258,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) return (ISC_R_SUCCESS); - CTRACE("query_addadditional"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional"); /* * Initialization. @@ -1301,7 +1314,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (result != ISC_R_SUCCESS) goto try_cache; - CTRACE("query_addadditional: db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: db_find"); /* * Since we are looking for authoritative data, we do not set @@ -1573,7 +1586,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { } addname: - CTRACE("query_addadditional: addname"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: addname"); /* * If we haven't added anything, then we're done. */ @@ -1613,7 +1626,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { } cleanup: - CTRACE("query_addadditional: cleanup"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: cleanup"); query_putrdataset(client, &rdataset); if (sigrdataset != NULL) query_putrdataset(client, &sigrdataset); @@ -1626,7 +1639,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (zone != NULL) dns_zone_detach(&zone); - CTRACE("query_addadditional: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: done"); return (eresult); } @@ -1744,7 +1757,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); - CTRACE("query_addadditional2"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2"); /* * We treat type A additional section processing as if it @@ -1776,14 +1789,16 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (result != ISC_R_SUCCESS) goto findauthdb; if (zone == NULL) { - CTRACE("query_addadditional2: auth zone not found"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: auth zone not found"); goto try_cache; } /* Is the cached DB up-to-date? */ result = query_iscachevalid(zone, cdb, NULL, cversion); if (result != ISC_R_SUCCESS) { - CTRACE("query_addadditional2: old auth additional cache"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: old auth additional cache"); query_discardcache(client, rdataset_base, additionaltype, type, &zone, &cdb, &cversion, &cnode, &cfname); @@ -1796,7 +1811,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { * ACL, since the result (not using this zone) would be same * regardless of the result. */ - CTRACE("query_addadditional2: negative auth additional cache"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: negative auth additional cache"); dns_db_closeversion(cdb, &cversion, ISC_FALSE); dns_db_detach(&cdb); dns_zone_detach(&zone); @@ -1813,7 +1829,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { } /* We've got an active cache. */ - CTRACE("query_addadditional2: auth additional cache"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: auth additional cache"); dns_db_closeversion(cdb, &cversion, ISC_FALSE); db = cdb; node = cnode; @@ -1837,7 +1854,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { goto try_cache; } - CTRACE("query_addadditional2: db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: db_find"); /* * Since we are looking for authoritative data, we do not set @@ -1922,7 +1939,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion); if (result != ISC_R_SUCCESS) { - CTRACE("query_addadditional2: old glue additional cache"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: old glue additional cache"); query_discardcache(client, rdataset_base, additionaltype, type, &zone, &cdb, &cversion, &cnode, &cfname); @@ -1931,14 +1949,15 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (cnode == NULL) { /* We have a negative cache. */ - CTRACE("query_addadditional2: negative glue additional cache"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addadditional2: negative glue additional cache"); dns_db_closeversion(cdb, &cversion, ISC_FALSE); dns_db_detach(&cdb); goto cleanup; } /* Cache hit. */ - CTRACE("query_addadditional2: glue additional cache"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: glue additional cache"); dns_db_closeversion(cdb, &cversion, ISC_FALSE); db = cdb; node = cnode; @@ -2121,7 +2140,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { } } - CTRACE("query_addadditional2: addname"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: addname"); /* * If we haven't added anything, then we're done. @@ -2140,7 +2159,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { fname = NULL; cleanup: - CTRACE("query_addadditional2: cleanup"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: cleanup"); if (rdataset != NULL) query_putrdataset(client, &rdataset); @@ -2159,7 +2178,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { if (zone != NULL) dns_zone_detach(&zone); - CTRACE("query_addadditional2: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: done"); return (eresult); } @@ -2174,7 +2193,7 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname, * 'fname', a name in the response message for 'client'. */ - CTRACE("query_addrdataset"); + CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset"); ISC_LIST_APPEND(fname->list, rdataset, link); @@ -2196,7 +2215,7 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname, additionalctx.rdataset = rdataset; (void)dns_rdataset_additionaldata(rdataset, query_addadditional2, &additionalctx); - CTRACE("query_addrdataset: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done"); } static isc_result_t @@ -2228,7 +2247,7 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset, * stored in 'dbuf'. In this case, query_addrrset() guarantees that * when it returns the name will either have been kept or released. */ - CTRACE("query_dns64"); + CTRACE(ISC_LOG_DEBUG(3), "query_dns64"); name = *namep; mname = NULL; mrdataset = NULL; @@ -2245,7 +2264,8 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset, * We've already got an RRset of the given name and type. * There's nothing else to do; */ - CTRACE("query_dns64: dns_message_findname succeeded: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_dns64: dns_message_findname succeeded: done"); if (dbuf != NULL) query_releasename(client, namep); return (ISC_R_SUCCESS); @@ -2376,7 +2396,7 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset, dns_message_puttemprdatalist(client->message, &dns64_rdatalist); } - CTRACE("query_dns64: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done"); return (result); } @@ -2395,7 +2415,7 @@ query_filter64(ns_client_t *client, dns_name_t **namep, isc_result_t result; unsigned int i; - CTRACE("query_filter64"); + CTRACE(ISC_LOG_DEBUG(3), "query_filter64"); INSIST(client->query.dns64_aaaaok != NULL); INSIST(client->query.dns64_aaaaoklen == dns_rdataset_count(rdataset)); @@ -2415,7 +2435,8 @@ query_filter64(ns_client_t *client, dns_name_t **namep, * We've already got an RRset of the given name and type. * There's nothing else to do; */ - CTRACE("query_filter64: dns_message_findname succeeded: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_filter64: dns_message_findname succeeded: done"); if (dbuf != NULL) query_releasename(client, namep); return; @@ -2514,7 +2535,7 @@ query_filter64(ns_client_t *client, dns_name_t **namep, if (dbuf != NULL) query_releasename(client, &name); - CTRACE("query_filter64: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done"); } static void @@ -2536,7 +2557,7 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, * stored in 'dbuf'. In this case, query_addrrset() guarantees that * when it returns the name will either have been kept or released. */ - CTRACE("query_addrrset"); + CTRACE(ISC_LOG_DEBUG(3), "query_addrrset"); name = *namep; rdataset = *rdatasetp; if (sigrdatasetp != NULL) @@ -2552,7 +2573,8 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, /* * We've already got an RRset of the given name and type. */ - CTRACE("query_addrrset: dns_message_findname succeeded: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addrrset: dns_message_findname succeeded: done"); if (dbuf != NULL) query_releasename(client, namep); if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) @@ -2591,7 +2613,7 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, ISC_LIST_APPEND(mname->list, sigrdataset, link); *sigrdatasetp = NULL; } - CTRACE("query_addrrset: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done"); } static inline isc_result_t @@ -2607,7 +2629,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, dns_clientinfomethods_t cm; dns_clientinfo_t ci; - CTRACE("query_addsoa"); + CTRACE(ISC_LOG_DEBUG(3), "query_addsoa"); /* * Initialization. */ @@ -2635,12 +2657,14 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, dns_name_clone(dns_db_origin(db), name); rdataset = query_newrdataset(client); if (rdataset == NULL) { + CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(db)) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) { + CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset"); eresult = DNS_R_SERVFAIL; goto cleanup; } @@ -2670,6 +2694,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version, * This is bad. We tried to get the SOA RR at the zone top * and it didn't work! */ + CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex"); eresult = DNS_R_SERVFAIL; } else { /* @@ -2734,7 +2759,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { dns_clientinfomethods_t cm; dns_clientinfo_t ci; - CTRACE("query_addns"); + CTRACE(ISC_LOG_DEBUG(3), "query_addns"); /* * Initialization. */ @@ -2752,21 +2777,24 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { */ result = dns_message_gettempname(client->message, &name); if (result != ISC_R_SUCCESS) { - CTRACE("query_addns: dns_message_gettempname failed: done"); + CTRACE(ISC_LOG_DEBUG(3), + "query_addns: dns_message_gettempname failed: done"); return (result); } dns_name_init(name, NULL); dns_name_clone(dns_db_origin(db), name); rdataset = query_newrdataset(client); if (rdataset == NULL) { - CTRACE("query_addns: query_newrdataset failed"); + CTRACE(ISC_LOG_ERROR, + "query_addns: query_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(db)) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) { - CTRACE("query_addns: query_newrdataset failed"); + CTRACE(ISC_LOG_ERROR, + "query_addns: query_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } @@ -2781,14 +2809,15 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { dns_rdatatype_ns, 0, client->now, rdataset, sigrdataset); } else { - CTRACE("query_addns: calling dns_db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find"); result = dns_db_findext(db, name, NULL, dns_rdatatype_ns, client->query.dboptions, 0, &node, fname, &cm, &ci, rdataset, sigrdataset); - CTRACE("query_addns: dns_db_find complete"); + CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete"); } if (result != ISC_R_SUCCESS) { - CTRACE("query_addns: " + CTRACE(ISC_LOG_ERROR, + "query_addns: " "dns_db_findrdataset or dns_db_find failed"); /* * This is bad. We tried to get the NS rdataset at the zone @@ -2805,7 +2834,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { } cleanup: - CTRACE("query_addns: cleanup"); + CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup"); query_putrdataset(client, &rdataset); if (sigrdataset != NULL) query_putrdataset(client, &sigrdataset); @@ -2814,7 +2843,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) { if (node != NULL) dns_db_detachnode(db, &node); - CTRACE("query_addns: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_addns: done"); return (eresult); } @@ -3082,7 +3111,7 @@ query_addbestns(ns_client_t *client) { dns_clientinfomethods_t cm; dns_clientinfo_t ci; - CTRACE("query_addbestns"); + CTRACE(ISC_LOG_DEBUG(3), "query_addbestns"); fname = NULL; zfname = NULL; rdataset = NULL; @@ -3287,7 +3316,7 @@ query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node, isc_result_t result; unsigned int count; - CTRACE("query_addds"); + CTRACE(ISC_LOG_DEBUG(3), "query_addds"); rname = NULL; rdataset = NULL; sigrdataset = NULL; @@ -3417,7 +3446,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db, dns_clientinfomethods_t cm; dns_clientinfo_t ci; - CTRACE("query_addwildcardproof"); + CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof"); fname = NULL; rdataset = NULL; sigrdataset = NULL; @@ -3781,9 +3810,10 @@ query_resume(isc_task_t *task, isc_event_t *event) { if (devent->sigrdataset != NULL) query_putrdataset(client, &devent->sigrdataset); isc_event_free(&event); - if (fetch_canceled) + if (fetch_canceled) { + CTRACE(ISC_LOG_ERROR, "fetch cancelled"); query_error(client, DNS_R_SERVFAIL, __LINE__); - else + } else query_next(client, ISC_R_CANCELED); /* * This may destroy the client. @@ -4047,8 +4077,11 @@ rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) if (*rdatasetp == NULL) { *rdatasetp = query_newrdataset(client); - if (*rdatasetp == NULL) + if (*rdatasetp == NULL) { + CTRACE(ISC_LOG_ERROR, + "rpz_ready: query_newrdataset failed"); return (DNS_R_SERVFAIL); + } } else if (dns_rdataset_isassociated(*rdatasetp)) { dns_rdataset_disassociate(*rdatasetp); } @@ -4187,6 +4220,7 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, st->r.r_rdataset = NULL; result = st->r.r_result; if (result == DNS_R_DELEGATION) { + CTRACE(ISC_LOG_ERROR, "RPZ recursing"); rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name, rpz_type, " rpz_rrset_find(1)", result); st->m.policy = DNS_RPZ_POLICY_ERROR; @@ -4372,8 +4406,10 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype, */ rpz_clean(zonep, dbp, nodep, rdatasetp); result = rpz_ready(client, rdatasetp); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + CTRACE(ISC_LOG_ERROR, "rpz_ready() failed"); return (DNS_R_SERVFAIL); + } *versionp = NULL; result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp); if (result != ISC_R_SUCCESS) @@ -4396,6 +4432,8 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype, if (result != ISC_R_SUCCESS) { rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, " allrdatasets()", result); + CTRACE(ISC_LOG_ERROR, + "rpz_find_p: allrdatasets failed"); return (DNS_R_SERVFAIL); } for (result = dns_rdatasetiter_first(rdsiter); @@ -4413,6 +4451,9 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype, rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, " rdatasetiter", result); + CTRACE(ISC_LOG_ERROR, + "rpz_find_p: rdatasetiter_destroy " + "failed"); return (DNS_R_SERVFAIL); } /* @@ -4467,6 +4508,8 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype, default: rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, "", result); + CTRACE(ISC_LOG_ERROR, + "rpz_find_p: unexpected result"); return (DNS_R_SERVFAIL); } } @@ -4696,6 +4739,8 @@ rpz_rewrite_ip_rrset(ns_client_t *client, rpz_type, " NS address rewrite rrset", result); } + CTRACE(ISC_LOG_ERROR, + "rpz_rewrite_ip_rrset: unexpected result"); return (DNS_R_SERVFAIL); } @@ -5330,6 +5375,7 @@ cleanup: rpz_match_clear(st); } if (st->m.policy == DNS_RPZ_POLICY_ERROR) { + CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy"); st->m.type = DNS_RPZ_TYPE_BAD; result = DNS_R_SERVFAIL; } @@ -5563,7 +5609,7 @@ query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) { dns_rdataset_t *neg, *negsig; isc_result_t result = ISC_R_NOMEMORY; - CTRACE("query_addnoqnameproof"); + CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof"); fname = NULL; neg = NULL; @@ -5977,7 +6023,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_clientinfo_t ci; ns_dbversion_t *dbversion; - CTRACE("redirect"); + CTRACE(ISC_LOG_DEBUG(3), "redirect"); if (client->view->redirect == NULL) return (ISC_FALSE); @@ -6044,7 +6090,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, dns_db_detach(&db); return (ISC_FALSE); } - CTRACE("redirect: found data: done"); + CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done"); dns_name_copy(found, name, NULL); if (dns_rdataset_isassociated(rdataset)) @@ -6109,11 +6155,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) isc_boolean_t nxrewrite = ISC_FALSE; dns_clientinfomethods_t cm; dns_clientinfo_t ci; + char errmsg[256]; isc_boolean_t associated; dns_section_t section; dns_ttl_t ttl; - CTRACE("query_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_find"); /* * One-time initialization. @@ -6205,11 +6252,15 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ dbuf = query_getnamebuf(client); if (dbuf == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: query_getnamebuf failed (1)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } fname = query_newname(client, dbuf, &b); if (fname == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: query_newname failed (1)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -6221,6 +6272,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } result = dns_name_copy(tname, fname, NULL); if (result != ISC_R_SUCCESS) { + CTRACE(ISC_LOG_ERROR, + "query_find: dns_name_copy failed"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -6249,7 +6302,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) type = qtype; restart: - CTRACE("query_find: restart"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: restart"); want_restart = ISC_FALSE; authoritative = ISC_FALSE; version = NULL; @@ -6326,8 +6379,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) inc_stats(client, dns_nsstatscounter_authrej); if (!PARTIALANSWER(client)) QUERY_ERROR(DNS_R_REFUSED); - } else + } else { + CTRACE(ISC_LOG_ERROR, + "query_find: query_getdb failed"); QUERY_ERROR(DNS_R_SERVFAIL); + } goto cleanup; } @@ -6360,24 +6416,30 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } db_find: - CTRACE("query_find: db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: db_find"); /* * We'll need some resources... */ dbuf = query_getnamebuf(client); if (dbuf == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: query_getnamebuf failed (2)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } fname = query_newname(client, dbuf, &b); rdataset = query_newrdataset(client); if (fname == NULL || rdataset == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: query_newname failed (2)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: query_newrdataset failed (2)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -6394,7 +6456,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_cache_updatestats(client->view->cache, result); resume: - CTRACE("query_find: resume"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: resume"); /* * Rate limit these responses to this client. @@ -6759,6 +6821,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) goto cleanup; } else { /* Unable to give root server referral. */ + CTRACE(ISC_LOG_ERROR, + "unable to give root server referral"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7025,11 +7089,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) if (fname == NULL) { dbuf = query_getnamebuf(client); if (dbuf == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: " + "query_getnamebuf failed (3)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } fname = query_newname(client, dbuf, &b); if (fname == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: " + "query_newname failed (3)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7128,6 +7198,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) if (fname == NULL || rdataset == NULL || sigrdataset == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: " + "failure getting " + "closest encloser"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7306,11 +7380,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) if (fname == NULL) { dbuf = query_getnamebuf(client); if (dbuf == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: " + "query_getnamebuf failed (4)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } fname = query_newname(client, dbuf, &b); if (fname == NULL) { + CTRACE(ISC_LOG_ERROR, + "query_find: " + "query_newname failed (4)"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7567,6 +7647,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) /* * Something has gone wrong. */ + snprintf(errmsg, sizeof(errmsg) - 1, + "query_find: unexpected error after resuming: %s", + isc_result_totext(result)); + CTRACE(ISC_LOG_ERROR, errmsg); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7625,6 +7709,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) rdsiter = NULL; result = dns_db_allrdatasets(db, node, version, 0, &rdsiter); if (result != ISC_R_SUCCESS) { + CTRACE(ISC_LOG_ERROR, + "query_find: type any; allrdatasets failed"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7759,12 +7845,18 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_rdatasetiter_destroy(&rdsiter); fname = query_newname(client, dbuf, &b); goto nxrrset_rrsig; - } else + } else { + CTRACE(ISC_LOG_ERROR, + "query_find: no matching rdatasets " + "in cache"); result = DNS_R_SERVFAIL; + } } dns_rdatasetiter_destroy(&rdsiter); if (result != ISC_R_NOMORE) { + CTRACE(ISC_LOG_ERROR, + "query_find: dns_rdatasetiter_destroy failed"); QUERY_ERROR(DNS_R_SERVFAIL); goto cleanup; } @@ -7988,7 +8080,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } addauth: - CTRACE("query_find: addauth"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: addauth"); /* * Add NS records to the authority section (if we haven't already * added them to the answer section). @@ -8016,7 +8108,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) dns_fixedname_name(&wildcardname), ISC_TRUE, ISC_FALSE); cleanup: - CTRACE("query_find: cleanup"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: cleanup"); /* * General cleanup. */ @@ -8124,7 +8216,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) query_send(client); ns_client_detach(&client); } - CTRACE("query_find: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_find: done"); return (eresult); } @@ -8212,7 +8304,7 @@ ns_query_start(ns_client_t *client) { unsigned int saved_extflags = client->extflags; unsigned int saved_flags = client->message->flags; - CTRACE("ns_query_start"); + CTRACE(ISC_LOG_DEBUG(3), "ns_query_start"); /* * Test only. diff --git a/bin/named/server.c b/bin/named/server.c index 72bbdd285f..eb7d02a0de 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -4684,6 +4684,9 @@ directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { static void scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { isc_boolean_t match_mapped = server->aclenv.match_mapped; +#ifdef HAVE_GEOIP + isc_boolean_t use_ecs = server->aclenv.geoip_use_ecs; +#endif ns_interfacemgr_scan(server->interfacemgr, verbose); /* @@ -4694,6 +4697,9 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { ns_interfacemgr_getaclenv(server->interfacemgr)); server->aclenv.match_mapped = match_mapped; +#ifdef HAVE_GEOIP + server->aclenv.geoip_use_ecs = use_ecs; +#endif } static isc_result_t @@ -5554,6 +5560,11 @@ load_configuration(const char *filename, ns_server_t *server, } else ns_geoip_load(NULL); ns_g_aclconfctx->geoip = ns_g_geoip; + + obj = NULL; + result = ns_config_get(maps, "geoip-use-ecs", &obj); + INSIST(result == ISC_R_SUCCESS); + ns_g_server->aclenv.geoip_use_ecs = cfg_obj_asboolean(obj); #endif /* HAVE_GEOIP */ /* diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 6e2fe3a3c3..f0584c3ac8 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -242,6 +242,7 @@ init_desc(void) { "SitNoMatch"); SET_NSSTATDESC(sitmatch, "source identity token - match", "SitMatch"); #endif + SET_NSSTATDESC(ecsopt, "EDNS client subnet option recieved", "ECSOpt"); INSIST(i == dns_nsstatscounter_max); /* Initialize resolver statistics */ diff --git a/bin/tests/system/acl/ns2/named6.conf b/bin/tests/system/acl/ns2/named6.conf new file mode 100644 index 0000000000..1e384fb0d8 --- /dev/null +++ b/bin/tests/system/acl/ns2/named6.conf @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + recursion no; + notify yes; + ixfr-from-differences yes; + check-integrity no; + allow-query-on { 10.53.0.2; }; +}; + +include "../../common/controls.conf"; + +zone "." { + type hint; + file "../../common/root.hint"; +}; + +zone "example" { + type master; + file "example.db"; +}; + +zone "tsigzone" { + type master; + file "tsigzone.db"; + allow-transfer { ecs 10.53/16; !10/8; }; +}; diff --git a/bin/tests/system/acl/ns2/named7.conf b/bin/tests/system/acl/ns2/named7.conf new file mode 100644 index 0000000000..1f1c9f333a --- /dev/null +++ b/bin/tests/system/acl/ns2/named7.conf @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + recursion no; + notify yes; + ixfr-from-differences yes; + check-integrity no; + allow-query-on { 10.53.0.2; }; +}; + +include "../../common/controls.conf"; + +view one { + match-clients { ecs 192.0.2/24; }; + + zone "." { + type hint; + file "../../common/root.hint"; + }; + + zone "example" { + type master; + file "example.db"; + }; +}; + +view two { + zone "." { + type hint; + file "../../common/root.hint"; + }; + + zone "example" { + type master; + file "example.db"; + }; +}; diff --git a/bin/tests/system/acl/tests.sh b/bin/tests/system/acl/tests.sh index b74c0c9f9f..27efd5cde8 100644 --- a/bin/tests/system/acl/tests.sh +++ b/bin/tests/system/acl/tests.sh @@ -150,5 +150,35 @@ $DIG +tcp soa example. \ @10.53.0.2 -b 10.53.0.3 -p 5300 > dig.out.${t} grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || { echo "I:test $t failed" ; status=1; } +echo "I:testing EDNS client-subnet ACL processing" +cp -f ns2/named6.conf ns2/named.conf +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' +sleep 5 + +# should fail +t=`expr $t + 1` +$DIG $DIGOPTS tsigzone. \ + @10.53.0.2 -b 10.53.0.2 axfr -p 5300 > dig.out.${t} +grep "^;" dig.out.${t} > /dev/null 2>&1 || { echo "I:test $t failed" ; status=1; } + +# should succeed +t=`expr $t + 1` +$DIG $DIGOPTS tsigzone. \ + @10.53.0.2 -b 10.53.0.2 +subnet="10.53.0/24" axfr -p 5300 > dig.out.${t} +grep "^;" dig.out.${t} > /dev/null 2>&1 && { echo "I:test $t failed" ; status=1; } + +echo "I:testing EDNS client-subnet response scope" +cp -f ns2/named7.conf ns2/named.conf +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' +sleep 5 + +t=`expr $t + 1` +$DIG example. soa @10.53.0.2 +subnet="10.53.0.1/32" -p 5300 > dig.out.${t} +grep "CLIENT-SUBNET.*10.53.0.1/32/0" dig.out.${t} > /dev/null || { echo "I:test $t failed" ; status=1; } + +t=`expr $t + 1` +$DIG example. soa @10.53.0.2 +subnet="192.0.2.128/32" -p 5300 > dig.out.${t} +grep "CLIENT-SUBNET.*192.0.2.128/32/24" dig.out.${t} > /dev/null || { echo "I:test $t failed" ; status=1; } + echo "I:exit status: $status" exit $status diff --git a/bin/tests/system/geoip/clean.sh b/bin/tests/system/geoip/clean.sh index 22d5e74466..6fa60e3e93 100644 --- a/bin/tests/system/geoip/clean.sh +++ b/bin/tests/system/geoip/clean.sh @@ -15,5 +15,5 @@ # PERFORMANCE OF THIS SOFTWARE. rm -f ns2/named.conf -rm -f ns2/example[1234567].db +rm -f ns2/example*.db rm -f dig.out.* rndc.out.* diff --git a/bin/tests/system/geoip/data/GeoIP.csv b/bin/tests/system/geoip/data/GeoIP.csv index f158a5b494..8e718540df 100644 --- a/bin/tests/system/geoip/data/GeoIP.csv +++ b/bin/tests/system/geoip/data/GeoIP.csv @@ -5,3 +5,4 @@ 10.53.0.5/32 CL 10.53.0.6/32 DE 10.53.0.7/32 EH +192.0.2/24 O1 diff --git a/bin/tests/system/geoip/data/GeoIP.dat b/bin/tests/system/geoip/data/GeoIP.dat index 027c1757c1..345092f371 100644 Binary files a/bin/tests/system/geoip/data/GeoIP.dat and b/bin/tests/system/geoip/data/GeoIP.dat differ diff --git a/bin/tests/system/geoip/data/README b/bin/tests/system/geoip/data/README index 47a6858f59..cea325b321 100644 --- a/bin/tests/system/geoip/data/README +++ b/bin/tests/system/geoip/data/README @@ -18,8 +18,8 @@ GeoIPDoain.dat: Domain Name GeoIPASNum.dat: AS Number GeoIPNetSpeed.dat: Net Speed -GeoIP.dat can also be generated using the open source 'geoip-csv-to-dat' -utility: +GeoIP.dat can also be egenerated using the open source 'geoip-csv-to-dat' +utility (also known in some packages as "geoip-generator"): $ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF "10.53.0.1","10.53.0.1","171245569","171245569","AU","Australia" @@ -29,4 +29,5 @@ $ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF "10.53.0.5","10.53.0.5","171245573","171245573","CL","Chile" "10.53.0.6","10.53.0.6","171245574","171245574","DE","Germany" "10.53.0.7","10.53.0.7","171245575","171245575","EH","Western Sahara" +"192.0.2.0","192.0.2.255","3221225984","3221226239","O1","Other" EOF diff --git a/bin/tests/system/geoip/ns2/named1.conf b/bin/tests/system/geoip/ns2/named1.conf index 367b5c7fa6..d9356c45e1 100644 --- a/bin/tests/system/geoip/ns2/named1.conf +++ b/bin/tests/system/geoip/ns2/named1.conf @@ -95,6 +95,14 @@ view seven { }; }; +view other { + match-clients { geoip db country country O1; }; + zone "example" { + type master; + file "exampleother.db"; + }; +}; + view none { match-clients { any; }; zone "example" { diff --git a/bin/tests/system/geoip/ns2/named10.conf b/bin/tests/system/geoip/ns2/named10.conf index 1ceece41cf..3594f615ab 100644 --- a/bin/tests/system/geoip/ns2/named10.conf +++ b/bin/tests/system/geoip/ns2/named10.conf @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -40,7 +40,7 @@ controls { }; view one { - match-clients { geoip domain one.de; }; + match-clients { geoip asnum "AS100001"; }; zone "example" { type master; file "example1.db"; @@ -48,7 +48,7 @@ view one { }; view two { - match-clients { geoip domain two.com; }; + match-clients { geoip asnum "AS100002"; }; zone "example" { type master; file "example2.db"; @@ -56,7 +56,7 @@ view two { }; view three { - match-clients { geoip domain three.com; }; + match-clients { geoip asnum "AS100003"; }; zone "example" { type master; file "example3.db"; @@ -64,7 +64,7 @@ view three { }; view four { - match-clients { geoip domain four.com; }; + match-clients { geoip asnum "AS100004"; }; zone "example" { type master; file "example4.db"; @@ -72,7 +72,7 @@ view four { }; view five { - match-clients { geoip domain five.es; }; + match-clients { geoip asnum "AS100005"; }; zone "example" { type master; file "example5.db"; @@ -80,7 +80,7 @@ view five { }; view six { - match-clients { geoip domain six.it; }; + match-clients { geoip asnum "AS100006"; }; zone "example" { type master; file "example6.db"; @@ -88,7 +88,7 @@ view six { }; view seven { - match-clients { geoip domain seven.org; }; + match-clients { geoip asnum "AS100007"; }; zone "example" { type master; file "example7.db"; diff --git a/bin/tests/system/geoip/ns2/named11.conf b/bin/tests/system/geoip/ns2/named11.conf index 85c0d32c34..1ceece41cf 100644 --- a/bin/tests/system/geoip/ns2/named11.conf +++ b/bin/tests/system/geoip/ns2/named11.conf @@ -40,7 +40,7 @@ controls { }; view one { - match-clients { geoip netspeed 0; }; + match-clients { geoip domain one.de; }; zone "example" { type master; file "example1.db"; @@ -48,7 +48,7 @@ view one { }; view two { - match-clients { geoip netspeed 1; }; + match-clients { geoip domain two.com; }; zone "example" { type master; file "example2.db"; @@ -56,7 +56,7 @@ view two { }; view three { - match-clients { geoip netspeed 2; }; + match-clients { geoip domain three.com; }; zone "example" { type master; file "example3.db"; @@ -64,13 +64,37 @@ view three { }; view four { - match-clients { geoip netspeed 3; }; + match-clients { geoip domain four.com; }; zone "example" { type master; file "example4.db"; }; }; +view five { + match-clients { geoip domain five.es; }; + zone "example" { + type master; + file "example5.db"; + }; +}; + +view six { + match-clients { geoip domain six.it; }; + zone "example" { + type master; + file "example6.db"; + }; +}; + +view seven { + match-clients { geoip domain seven.org; }; + zone "example" { + type master; + file "example7.db"; + }; +}; + view none { match-clients { any; }; zone "example" { diff --git a/bin/tests/system/geoip/ns2/named12.conf b/bin/tests/system/geoip/ns2/named12.conf index a650a635d2..85c0d32c34 100644 --- a/bin/tests/system/geoip/ns2/named12.conf +++ b/bin/tests/system/geoip/ns2/named12.conf @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,10 +18,6 @@ controls { /* empty */ }; -acl blocking { - geoip db country country AU; -}; - options { query-source address 10.53.0.2; notify-source 10.53.0.2; @@ -32,7 +28,6 @@ options { listen-on-v6 { none; }; recursion no; geoip-directory "../data"; - blackhole { blocking; }; }; key rndc_key { @@ -43,3 +38,43 @@ key rndc_key { controls { inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; }; + +view one { + match-clients { geoip netspeed 0; }; + zone "example" { + type master; + file "example1.db"; + }; +}; + +view two { + match-clients { geoip netspeed 1; }; + zone "example" { + type master; + file "example2.db"; + }; +}; + +view three { + match-clients { geoip netspeed 2; }; + zone "example" { + type master; + file "example3.db"; + }; +}; + +view four { + match-clients { geoip netspeed 3; }; + zone "example" { + type master; + file "example4.db"; + }; +}; + +view none { + match-clients { any; }; + zone "example" { + type master; + file "example.db.in"; + }; +}; diff --git a/bin/tests/system/geoip/ns2/named13.conf b/bin/tests/system/geoip/ns2/named13.conf index f92d25216c..a650a635d2 100644 --- a/bin/tests/system/geoip/ns2/named13.conf +++ b/bin/tests/system/geoip/ns2/named13.conf @@ -18,6 +18,10 @@ controls { /* empty */ }; +acl blocking { + geoip db country country AU; +}; + options { query-source address 10.53.0.2; notify-source 10.53.0.2; @@ -28,6 +32,7 @@ options { listen-on-v6 { none; }; recursion no; geoip-directory "../data"; + blackhole { blocking; }; }; key rndc_key { @@ -38,75 +43,3 @@ key rndc_key { controls { inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; }; - -acl gAU { geoip db country country AU; }; -acl gUS { geoip db country country US; }; -acl gGB { geoip db country country GB; }; -acl gCA { geoip db country country CA; }; -acl gCL { geoip db country country CL; }; -acl gDE { geoip db country country DE; }; -acl gEH { geoip db country country EH; }; - -view one { - match-clients { gAU; }; - zone "example" { - type master; - file "example1.db"; - }; -}; - -view two { - match-clients { gUS; }; - zone "example" { - type master; - file "example2.db"; - }; -}; - -view three { - match-clients { gGB; }; - zone "example" { - type master; - file "example3.db"; - }; -}; - -view four { - match-clients { gCA; }; - zone "example" { - type master; - file "example4.db"; - }; -}; - -view five { - match-clients { gCL; }; - zone "example" { - type master; - file "example5.db"; - }; -}; - -view six { - match-clients { gDE; }; - zone "example" { - type master; - file "example6.db"; - }; -}; - -view seven { - match-clients { gEH; }; - zone "example" { - type master; - file "example7.db"; - }; -}; - -view none { - match-clients { any; }; - zone "example" { - type master; - file "example.db.in"; - }; -}; diff --git a/bin/tests/system/geoip/ns2/named14.conf b/bin/tests/system/geoip/ns2/named14.conf new file mode 100644 index 0000000000..10c6d9becb --- /dev/null +++ b/bin/tests/system/geoip/ns2/named14.conf @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +// NS2 + +controls { /* empty */ }; + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port 5300; + pid-file "named.pid"; + listen-on { 127.0.0.1; 10.53.0.2; }; + listen-on-v6 { none; }; + recursion no; + geoip-directory "../data"; + geoip-use-ecs no; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; +}; + +acl gAU { geoip db country country AU; }; +acl gUS { geoip db country country US; }; +acl gGB { geoip db country country GB; }; +acl gCA { geoip db country country CA; }; +acl gCL { geoip db country country CL; }; +acl gDE { geoip db country country DE; }; +acl gEH { geoip db country country EH; }; + +view one { + match-clients { gAU; }; + zone "example" { + type master; + file "example1.db"; + }; +}; + +view two { + match-clients { gUS; }; + zone "example" { + type master; + file "example2.db"; + }; +}; + +view three { + match-clients { gGB; }; + zone "example" { + type master; + file "example3.db"; + }; +}; + +view four { + match-clients { gCA; }; + zone "example" { + type master; + file "example4.db"; + }; +}; + +view five { + match-clients { gCL; }; + zone "example" { + type master; + file "example5.db"; + }; +}; + +view six { + match-clients { gDE; }; + zone "example" { + type master; + file "example6.db"; + }; +}; + +view seven { + match-clients { gEH; }; + zone "example" { + type master; + file "example7.db"; + }; +}; + +view none { + match-clients { any; }; + zone "example" { + type master; + file "examplebogus.db"; + }; +}; diff --git a/bin/tests/system/geoip/setup.sh b/bin/tests/system/geoip/setup.sh index 5de40eb6ef..2aaeaca15f 100644 --- a/bin/tests/system/geoip/setup.sh +++ b/bin/tests/system/geoip/setup.sh @@ -21,7 +21,7 @@ $SHELL clean.sh cp ns2/named1.conf ns2/named.conf -for i in 1 2 3 4 5 6 7; do +for i in 1 2 3 4 5 6 7 other bogus; do cp ns2/example.db.in ns2/example${i}.db echo "@ IN TXT \"$i\"" >> ns2/example$i.db done diff --git a/bin/tests/system/geoip/tests.sh b/bin/tests/system/geoip/tests.sh index e7ab56a57b..19d05ce66f 100644 --- a/bin/tests/system/geoip/tests.sh +++ b/bin/tests/system/geoip/tests.sh @@ -38,6 +38,30 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP country database by code (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/0" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:checking response scope using client subnet ($n)" +ret=0 +$DIG +tcp -p5300 @10.53.0.2 txt example -b 127.0.0.1 +subnet="10.53.0.1/32" > dig.out.ns2.test$n.1 || ret=1 +grep 'CLIENT-SUBNET.*10.53.0.1/32/32' dig.out.ns2.test$n.1 > /dev/null || ret=1 +$DIG +tcp -p5300 @10.53.0.2 txt example -b 127.0.0.1 +subnet="192.0.2.64/32" > dig.out.ns2.test$n.2 || ret=1 +grep 'CLIENT-SUBNET.*192.0.2.64/32/24' dig.out.ns2.test$n.2 > /dev/null || ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" cp -f ns2/named2.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' @@ -115,6 +139,21 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP region database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + + echo "I:reloading server" cp -f ns2/named6.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' @@ -134,6 +173,20 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP city database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" cp -f ns2/named7.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' @@ -153,6 +206,20 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP isp database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" cp -f ns2/named8.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' @@ -172,6 +239,20 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP org database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" cp -f ns2/named9.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' @@ -191,11 +272,58 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP asnum database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" cp -f ns2/named10.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' sleep 3 +n=`expr $n + 1` +echo "I:checking GeoIP asnum database - ASNNNN only ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:checking GeoIP domain database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + +echo "I:reloading server" +cp -f ns2/named11.conf ns2/named.conf +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' +sleep 3 + n=`expr $n + 1` echo "I:checking GeoIP domain database ($n)" ret=0 @@ -211,7 +339,7 @@ done status=`expr $status + $ret` echo "I:reloading server" -cp -f ns2/named11.conf ns2/named.conf +cp -f ns2/named12.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' sleep 3 @@ -229,8 +357,22 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:checking GeoIP netspeed database (using client subnet) ($n)" +ret=0 +lret=0 +for i in 1 2 3 4; do + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:reloading server" -cp -f ns2/named12.conf ns2/named.conf +cp -f ns2/named13.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' sleep 3 @@ -243,7 +385,7 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 status 2>&1 > rndc.out.ns2.tes status=`expr $status + $ret` echo "I:reloading server" -cp -f ns2/named13.conf ns2/named.conf +cp -f ns2/named14.conf ns2/named.conf $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' sleep 3 @@ -261,5 +403,29 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +echo "I:reloading server" +cp -f ns2/named14.conf ns2/named.conf +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' +sleep 3 + +n=`expr $n + 1` +echo "I:checking geoip-use-ecs ($n)" +ret=0 +lret=0 +for i in 1 2 3 4 5 6 7; do + $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 + j=`cat dig.out.ns2.test$n.$i | tr -d '"'` + [ "$i" = "$j" ] || lret=1 + [ $lret -eq 1 ] && break + + $DIG $DIGOPTS txt example -b 127.0.0.1 +subnet="10.53.0.$i/32" > dig.out.ns2.test$n.ecs.$i || lret=1 + j=`cat dig.out.ns2.test$n.ecs.$i | tr -d '"'` + [ "$j" = "bogus" ] || lret=1 + [ $lret -eq 1 ] && break +done +[ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/bin/tests/system/sit/bad-sit-badhex.conf b/bin/tests/system/sit/bad-sit-badhex.conf new file mode 100644 index 0000000000..6b84d8a6a1 --- /dev/null +++ b/bin/tests/system/sit/bad-sit-badhex.conf @@ -0,0 +1,3 @@ +options { + sit-secret "012345678901234567890123456789012345678901234567890123456789012"; +}; diff --git a/bin/tests/system/sit/bad-sit-toolong.conf b/bin/tests/system/sit/bad-sit-toolong.conf new file mode 100644 index 0000000000..aec4d252c8 --- /dev/null +++ b/bin/tests/system/sit/bad-sit-toolong.conf @@ -0,0 +1,3 @@ +options { + sit-secret "01234567890123456789012345678901234567890123456789012345678901234567890"; +}; diff --git a/bin/tests/system/sit/tests.sh b/bin/tests/system/sit/tests.sh index fa1a71abb0..5842a98714 100755 --- a/bin/tests/system/sit/tests.sh +++ b/bin/tests/system/sit/tests.sh @@ -32,6 +32,15 @@ havetc() { grep 'flags:.* tc[^;]*;' $1 > /dev/null } +for bad in bad*.conf +do + ret=0 + echo "I:checking that named-checkconf detects error in $bad" + $CHECKCONF $bad > /dev/null 2>&1 + if [ $? != 1 ]; then echo "I:failed"; ret=1; fi + status=`expr $status + $ret` +done + n=`expr $n + 1` echo "I:checking SIT token returned to empty SIT option ($n)" ret=0 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 7562a331ed..8d34bf0b4f 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -2564,10 +2564,10 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. lwres statement in named.conf. - The number of client queries that the lwresd - daemon is able to serve can be set using the - and - statements in the configuration. + The number of client queries that the lwresd + daemon is able to serve can be set using the + and + statements in the configuration. @@ -3444,63 +3444,6 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. - - - When BIND 9 is built with GeoIP support, - ACLs can also be used for geographic access restrictions. - This is done by specifying an ACL element of the form: - geoip db database field value - - - The field indicates which field - to search for a match. Available fields are "country", - "region", "city", "continent", "postal" (postal code), - "metro" (metro code), "area" (area code), "tz" (timezone), - "isp", "org", "asnum", "domain" and "netspeed". - - - value is the value to searched for - within the database. A string may be quoted if it contains - spaces or other special characters. If this is a "country" - search and the string is two characters long, then it must be a - standard ISO-3166-1 two-letter country code, and if it is three - characters long then it must be an ISO-3166-1 three-letter - country code; otherwise it is the full name of the country. - Similarly, if this is a "region" search and the string is - two characters long, then it must be a standard two-letter state - or province abbreviation; otherwise it is the full name of the - state or province. - - - The database field indicates which - GeoIP database to search for a match. In most cases this is - unnecessary, because most search fields can only be found in - a single database. However, searches for country can be - answered from the "city", "region", or "country" databases, - and searches for region (i.e., state or province) can be - answered from the "city" or "region" databases. For these - search types, specifying a database - will force the query to be answered from that database and no - other. If database is not - specified, then these queries will be answered from the "city", - database if it is installed, or the "region" database if it is - installed, or the "country" database, in that order. - - - Some example GeoIP ACLs: - - geoip country US; -geoip country JAP; -geoip db country country Canada; -geoip db region region WA; -geoip city "San Francisco"; -geoip region Oklahoma; -geoip postal 95062; -geoip tz "America/Los_Angeles"; -geoip org "Internet Systems Consortium"; - - - <command>controls</command> Statement Grammar @@ -4718,32 +4661,32 @@ badresp:1,adberr:0,findfail:0,valfail:0] minimum number of dots in a relative domain name that should result in an exact match lookup before search path elements are appended. - - - The statement specifies the number - of worker threads the lightweight resolver will dedicate to serving - clients. By default the number is the same as the number of CPUs on - the system; this can be overridden using the - command line option when starting the server. - - - The specifies - the number of client objects per thread the lightweight - resolver should create to serve client queries. - By default, if the lightweight resolver runs as a part - of named, 256 client objects are - created for each task; if it runs as lwresd, - 1024 client objects are created for each thread. The maximum - value is 32768; higher values will be silently ignored and - the maximum will be used instead. - Note that setting too high a value may overconsume - system resources. - - - The maximum number of client queries that the lightweight - resolver can handle at any one time equals - times . - + + + The statement specifies the number + of worker threads the lightweight resolver will dedicate to serving + clients. By default the number is the same as the number of CPUs on + the system; this can be overridden using the + command line option when starting the server. + + + The specifies + the number of client objects per thread the lightweight + resolver should create to serve client queries. + By default, if the lightweight resolver runs as a part + of named, 256 client objects are + created for each task; if it runs as lwresd, + 1024 client objects are created for each thread. The maximum + value is 32768; higher values will be silently ignored and + the maximum will be used instead. + Note that setting too high a value may overconsume + system resources. + + + The maximum number of client queries that the lightweight + resolver can handle at any one time equals + times . + <command>masters</command> Statement Grammar @@ -4855,6 +4798,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] allow-update { address_match_list }; allow-update-forwarding { address_match_list }; automatic-interface-scan { yes_or_no }; + geoip-use-ecs yes_or_no; update-check-ksk yes_or_no; dnssec-update-mode ( maintain | no-resign ); dnssec-dnskey-kskonly yes_or_no; @@ -5793,7 +5737,7 @@ options { For convenience, TTL-style time unit suffixes can be used to specify the NTA lifetime in seconds, minutes or hours. defaults to - one hour. It cannot exceed one day. + one hour. It cannot exceed one day. @@ -5802,31 +5746,31 @@ options { nta-recheck - Species how often to check whether negative - trust anchors added via rndc nta - are still necessary. + Species how often to check whether negative + trust anchors added via rndc nta + are still necessary. - A negative trust anchor is normally used when a - domain has stopped validating due to operator error; - it temporarily disables DNSSEC validation for that - domain. In the interest of ensuring that DNSSEC - validation is turned back on as soon as possible, - named will periodically send a - query to the domain, ignoring negative trust anchors, - to find out whether it can now be validated. If so, - the negative trust anchor is allowed to expire early. + A negative trust anchor is normally used when a + domain has stopped validating due to operator error; + it temporarily disables DNSSEC validation for that + domain. In the interest of ensuring that DNSSEC + validation is turned back on as soon as possible, + named will periodically send a + query to the domain, ignoring negative trust anchors, + to find out whether it can now be validated. If so, + the negative trust anchor is allowed to expire early. - Validity checks can be disabled for an individual - NTA by using rndc nta -f, or - for all NTA's by setting - to zero. + Validity checks can be disabled for an individual + NTA by using rndc nta -f, or + for all NTA's by setting + to zero. For convenience, TTL-style time unit suffixes can be - used to specify the NTA recheck interval in seconds, - minutes or hours. The default is five minutes. + used to specify the NTA recheck interval in seconds, + minutes or hours. The default is five minutes. @@ -6237,6 +6181,20 @@ options { + + geoip-use-ecs + + + When BIND is compiled with GeoIP support and configured + with "geoip" ACL elements, this option indicates whether + the EDNS Client Subnet option, if present in a request, + should be used for matching against the GeoIP database. + The default is + geoip-use-ecs yes. + + + + has-old-clients @@ -6421,12 +6379,16 @@ options { - sit-secret + sit-secret + If set, this is a shared secret used for generating and verifying Source Identity Token EDNS options within a anycast cluster. If not set the system - will generate a random secret at startup. + will generate a random secret at startup. The + shared secret is encoded as a hex string and needs + to be 128 bits for AES128, 160 bits for SHA1 and + 256 bits for SHA256. @@ -9016,24 +8978,24 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; masterfile-style - - Specifies the formatting of zone files during dump - when the is - text. (This option is ignored - with any other .) - - - When set to relative, - records are printed in a multi-line format with owner - names expressed relative to a shared origin. When set - to full, records are printed in - a single-line format with absolute owner names. - The full format is most suitable - when a zone file needs to be processed automatically - by a script. The relative format - is more human-readable, and is thus suitable when a - zone is to be edited by hand. The default is - relative. + + Specifies the formatting of zone files during dump + when the is + text. (This option is ignored + with any other .) + + + When set to relative, + records are printed in a multi-line format with owner + names expressed relative to a shared origin. When set + to full, records are printed in + a single-line format with absolute owner names. + The full format is most suitable + when a zone file needs to be processed automatically + by a script. The relative format + is more human-readable, and is thus suitable when a + zone is to be edited by hand. The default is + relative. @@ -9046,8 +9008,8 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; initial value (minimum) and maximum number of recursive simultaneous clients for any given query (<qname,qtype,qclass>) that the server will accept - before dropping additional clients. - named will attempt to + before dropping additional clients. + named will attempt to self tune this value and changes will be logged. The default values are 10 and 100. @@ -10560,15 +10522,15 @@ rate-limit { The request-expire clause determines - whether the local server, when acting as a slave, will - request the EDNS EXPIRE value. The EDNS EXPIRE value - indicates the remaining time before the zone data will - expire and need to be be refreshed. This is used - when a secondary server transfers a zone from another - secondary server; when transferring from the primary, the - expiration timer is set from the EXPIRE field of the SOA - record instead. - The default is yes. + whether the local server, when acting as a slave, will + request the EDNS EXPIRE value. The EDNS EXPIRE value + indicates the remaining time before the zone data will + expire and need to be be refreshed. This is used + when a secondary server transfers a zone from another + secondary server; when transferring from the primary, the + expiration timer is set from the EXPIRE field of the SOA + record instead. + The default is yes. @@ -12455,11 +12417,11 @@ example.com. NS ns2.example.net. When set to serial-update-method date;, the - new SOA serial number will be the current date - in the form "YYYYMMDD", followed by two zeroes, - unless the existing serial number is already greater - than or equal to that value, in which case it is - incremented by one. + new SOA serial number will be the current date + in the form "YYYYMMDD", followed by two zeroes, + unless the existing serial number is already greater + than or equal to that value, in which case it is + incremented by one. @@ -16181,11 +16143,11 @@ HOST-127.EXAMPLE. MX 0 . Access Control Lists Access Control Lists (ACLs) are address match lists that - you can set up and nickname for future use in allow-notify, - allow-query, allow-query-on, - allow-recursion, allow-recursion-on, + you can set up and nickname for future use in + allow-notify, allow-query, + allow-query-on, allow-recursion, blackhole, allow-transfer, - etc. + match-clients, etc. Using ACLs allows you to have finer control over who can access @@ -16195,11 +16157,19 @@ HOST-127.EXAMPLE. MX 0 . It is a good idea to use ACLs, and to control access to your server. Limiting access to your server by - outside parties can help prevent spoofing and denial of service (DoS) attacks against - your server. + outside parties can help prevent spoofing and denial of service + (DoS) attacks against your server. - Here is an example of how to properly apply ACLs: + ACLs match clients on the basis of up to three characteristics: + 1) The client's IP address; 2) the TSIG or SIG(0) key that was + used to sign the request, if any; and 3) an address prefix + encoded in an EDNS Client Subnet option, if any. + + + ACLs + + Here is an example of ACLs based on client addresses: @@ -16232,10 +16202,137 @@ zone "example.com" { - This allows recursive queries of the server from the outside - unless recursion has been previously disabled. + This allows authoritative queries for "example.com" from any + address, but recursive queries only from the networks specified + in "our-nets", and no queries at all from the networks + specified in "bogusnets". + + + In addition to network addresses and prefixes, which are + matched against the source address of the DNS request, ACLs + may include elements, which specify the + name of a TSIG or SIG(0) key, or + elements, which specify a network prefix but are only matched + if that prefix matches an EDNS client subnet option included + in the request. + + + The EDNS Client Subnet (ECS) option is used by a recursive + resolver to inform an authoritative name server of the network + address block from which the original query was received, enabling + authoritative servers to give different answers to the same + resolver for different resolver clients. An ACL containing + an element of the form + ecs prefix + will match if a request arrives in containing an ECS option + encoding an address within that prefix. If the request has no + ECS option, then "ecs" elements are simply ignored. Addresses + in ACLs that are not prefixed with "ecs" are matched only + against the source address. + + + When BIND 9 is built with GeoIP support, + ACLs can also be used for geographic access restrictions. + This is done by specifying an ACL element of the form: + geoip db database field value + + + The field indicates which field + to search for a match. Available fields are "country", + "region", "city", "continent", "postal" (postal code), + "metro" (metro code), "area" (area code), "tz" (timezone), + "isp", "org", "asnum", "domain" and "netspeed". + + + value is the value to search + for within the database. A string may be quoted if it + contains spaces or other special characters. If this is + an "asnum" search, then the leading "ASNNNN" string can be + used, otherwise the full description must be used (e.g. + "ASNNNN Example Company Name"). If this is a "country" + search and the string is two characters long, then it must + be a standard ISO-3166-1 two-letter country code, and if it + is three characters long then it must be an ISO-3166-1 + three-letter country code; otherwise it is the full name + of the country. Similarly, if this is a "region" search + and the string is two characters long, then it must be a + standard two-letter state or province abbreviation; + otherwise it is the full name of the state or province. + + + The database field indicates which + GeoIP database to search for a match. In most cases this is + unnecessary, because most search fields can only be found in + a single database. However, searches for country can be + answered from the "city", "region", or "country" databases, + and searches for region (i.e., state or province) can be + answered from the "city" or "region" databases. For these + search types, specifying a database + will force the query to be answered from that database and no + other. If database is not + specified, then these queries will be answered from the "city", + database if it is installed, or the "region" database if it is + installed, or the "country" database, in that order. + + + By default, if a DNS query includes an EDNS Client Subnet (ECS) + option which encodes a non-zero address prefix, then GeoIP ACLs + will be matched against that address prefix. Otherwise, they + are matched against the source address of the query. To + prevent GeoIP ACLs from matching against ECS options, set + the geoip-use-ecs to no. + + + Some example GeoIP ACLs: + + geoip country US; +geoip country JAP; +geoip db country country Canada; +geoip db region region WA; +geoip city "San Francisco"; +geoip region Oklahoma; +geoip postal 95062; +geoip tz "America/Los_Angeles"; +geoip org "Internet Systems Consortium"; + + + + ACLs use a "first-match" logic rather than "best-match": + if an address prefix matches an ACL element, then that ACL + is considered to have matched even if a later element would + have matched more specifically. For example, the ACL + { 10/8; !10.0.0.1; } would actually + match a query from 10.0.0.1, because the first element + indicated that the query should be accepted, and the second + element is ignored. + + + When using "nested" ACLs (that is, ACLs included or referenced + within other ACLs), a negative match of a nested ACL will + the containing ACL to continue looking for matches. This + enables complex ACLs to be constructed, in which multiple + client characteristics can be checked at the same time. For + example, to construct an ACL which allows queries only when + it originates from a particular network and + only when it is signed with a particular key, use: + + +allow-query { !{ !10/8; any; }; key example; }; + + + Within the nested ACL, any address that is + not in the 10/8 network prefix will + be rejected, and this will terminate processing of the + ACL. Any address that is in the 10/8 + network prefix will be accepted, but this causes a negative + match of the nested ACL, so the containing ACL continues + processing. The query will then be accepted if it is signed + by the key "example", and rejected otherwise. The ACL, then, + will only matches when both conditions + are true. + <command>Chroot</command> and <command>Setuid</command> diff --git a/lib/bind9/check.c b/lib/bind9/check.c index a8d5e00aa6..e1081a5647 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -24,10 +24,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -35,6 +37,18 @@ #include #include +#ifdef ISC_PLATFORM_USESIT +#ifdef AES_SIT +#include +#endif +#ifdef HMAC_SHA1_SIT +#include +#endif +#ifdef HMAC_SHA256_SIT +#include +#endif +#endif + #include #include #include @@ -1186,6 +1200,52 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, "(%d seconds)", recheck, lifetime); } +#ifdef ISC_PLATFORM_USESIT + obj = NULL; + (void) cfg_map_get(options, "sit-secret", &obj); + if (obj != NULL) { + isc_buffer_t b; + unsigned char secret[32]; + + memset(secret, 0, sizeof(secret)); + isc_buffer_init(&b, secret, sizeof(secret)); + tresult = isc_hex_decodestring(cfg_obj_asstring(obj), &b); + if (tresult == ISC_R_NOSPACE) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "sit-secret: too long"); + } else if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "sit-secret: invalid hex string"); + } + if (tresult != ISC_R_SUCCESS) + result = tresult; +#ifdef AES_SIT + if (tresult == ISC_R_SUCCESS && + isc_buffer_usedlength(&b) != ISC_AES128_KEYLENGTH) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "AES sit-secret must be on 128 bits"); + result = ISC_R_RANGE; + } +#endif +#ifdef HMAC_SHA1_SIT + if (tresult == ISC_R_SUCCESS && + isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "SHA1 sit-secret must be on 160 bits"); + result = ISC_R_RANGE; + } +#endif +#ifdef HMAC_SHA256_SIT + if (tresult == ISC_R_SUCCESS && + isc_buffer_usedlength(&b) != ISC_SHA256_DIGESTLENGTH) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "SHA256 sit-secret must be on 256 bits"); + result = ISC_R_RANGE; + } +#endif + } +#endif + return (result); } diff --git a/lib/dns/acl.c b/lib/dns/acl.c index 880fc3648e..41c865585a 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acl.c,v 1.55 2011/06/17 23:47:49 tbox Exp $ */ - /*! \file */ #include @@ -194,10 +192,25 @@ dns_acl_match(const isc_netaddr_t *reqaddr, int *match, const dns_aclelement_t **matchelt) { - isc_uint16_t bitlen, family; + return (dns_acl_match2(reqaddr, reqsigner, NULL, 0, NULL, acl, env, + match, matchelt)); +} + +isc_result_t +dns_acl_match2(const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, + const isc_netaddr_t *ecs, + isc_uint8_t ecslen, + isc_uint8_t *scope, + const dns_acl_t *acl, + const dns_aclenv_t *env, + int *match, + const dns_aclelement_t **matchelt) +{ + isc_uint16_t bitlen; isc_prefix_t pfx; isc_radix_node_t *node = NULL; - const isc_netaddr_t *addr; + const isc_netaddr_t *addr = reqaddr; isc_netaddr_t v4addr; isc_result_t result; int match_num = -1; @@ -205,20 +218,19 @@ dns_acl_match(const isc_netaddr_t *reqaddr, REQUIRE(reqaddr != NULL); REQUIRE(matchelt == NULL || *matchelt == NULL); + REQUIRE(ecs != NULL || scope == NULL); - if (env == NULL || env->match_mapped == ISC_FALSE || - reqaddr->family != AF_INET6 || - !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6)) - addr = reqaddr; - else { - isc_netaddr_fromv4mapped(&v4addr, reqaddr); + if (env != NULL && env->match_mapped && + addr->family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&addr->type.in6)) + { + isc_netaddr_fromv4mapped(&v4addr, addr); addr = &v4addr; } /* Always match with host addresses. */ - family = addr->family; - bitlen = family == AF_INET6 ? 128 : 32; - NETADDR_TO_PREFIX_T(addr, pfx, bitlen); + bitlen = (addr->family == AF_INET6) ? 128 : 32; + NETADDR_TO_PREFIX_T(addr, pfx, bitlen, ISC_FALSE); /* Assume no match. */ *match = 0; @@ -228,37 +240,75 @@ dns_acl_match(const isc_netaddr_t *reqaddr, /* Found a match. */ if (result == ISC_R_SUCCESS && node != NULL) { - match_num = node->node_num[ISC_IS6(family)]; - if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE) + int off = ISC_RADIX_OFF(&pfx); + match_num = node->node_num[off]; + if (*(isc_boolean_t *) node->data[off]) *match = match_num; else *match = -match_num; } + isc_refcount_destroy(&pfx.refcount); + + /* + * If ecs is not NULL, we search the radix tree again to + * see if we find a better match on an ECS node + */ + if (ecs != NULL) { + node = NULL; + addr = ecs; + + if (env != NULL && env->match_mapped && + addr->family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&addr->type.in6)) + { + isc_netaddr_fromv4mapped(&v4addr, addr); + addr = &v4addr; + } + + NETADDR_TO_PREFIX_T(addr, pfx, ecslen, ISC_TRUE); + + result = isc_radix_search(acl->iptable->radix, &node, &pfx); + if (result == ISC_R_SUCCESS && node != NULL) { + int off = ISC_RADIX_OFF(&pfx); + if (match_num == -1 || + node->node_num[off] < match_num) + { + match_num = node->node_num[off]; + if (scope != NULL) + *scope = node->bit; + if (*(isc_boolean_t *) node->data[off]) + *match = match_num; + else + *match = -match_num; + } + } + + isc_refcount_destroy(&pfx.refcount); + } + /* Now search non-radix elements for a match with a lower node_num. */ for (i = 0; i < acl->length; i++) { dns_aclelement_t *e = &acl->elements[i]; /* Already found a better match? */ if (match_num != -1 && match_num < e->node_num) { - isc_refcount_destroy(&pfx.refcount); - return (ISC_R_SUCCESS); + break; } - if (dns_aclelement_match(reqaddr, reqsigner, - e, env, matchelt)) { + if (dns_aclelement_match2(reqaddr, reqsigner, ecs, ecslen, + scope, e, env, matchelt)) + { if (match_num == -1 || e->node_num < match_num) { - if (e->negative == ISC_TRUE) + if (e->negative) *match = -e->node_num; else *match = e->node_num; } - isc_refcount_destroy(&pfx.refcount); - return (ISC_R_SUCCESS); + break; } } - isc_refcount_destroy(&pfx.refcount); return (ISC_R_SUCCESS); } @@ -349,7 +399,7 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos) #endif /* reverse sense of positives if this is a negative acl */ - if (!pos && source->elements[i].negative == ISC_FALSE) { + if (!pos && !source->elements[i].negative) { dest->elements[nelem + i].negative = ISC_TRUE; } else { dest->elements[nelem + i].negative = @@ -386,10 +436,29 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_aclelement_t *e, const dns_aclenv_t *env, const dns_aclelement_t **matchelt) +{ + return (dns_aclelement_match2(reqaddr, reqsigner, NULL, 0, NULL, + e, env, matchelt)); +} + +isc_boolean_t +dns_aclelement_match2(const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, + const isc_netaddr_t *ecs, + isc_uint8_t ecslen, + isc_uint8_t *scope, + const dns_aclelement_t *e, + const dns_aclenv_t *env, + const dns_aclelement_t **matchelt) { dns_acl_t *inner = NULL; int indirectmatch; isc_result_t result; +#ifdef HAVE_GEOIP + const isc_netaddr_t *addr = NULL; +#endif + + REQUIRE(ecs != NULL || scope == NULL); switch (e->type) { case dns_aclelementtype_keyname: @@ -421,15 +490,17 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, case dns_aclelementtype_geoip: if (env == NULL || env->geoip == NULL) return (ISC_FALSE); - return (dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem)); + addr = (env->geoip_use_ecs && ecs != NULL) ? ecs : reqaddr; + return (dns_geoip_match(addr, scope, env->geoip, + &e->geoip_elem)); #endif default: /* Should be impossible. */ INSIST(0); } - result = dns_acl_match(reqaddr, reqsigner, inner, env, - &indirectmatch, matchelt); + result = dns_acl_match2(reqaddr, reqsigner, ecs, ecslen, scope, + inner, env, &indirectmatch, matchelt); INSIST(result == ISC_R_SUCCESS); /* @@ -438,7 +509,6 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, * surprise positive match through double negation. * XXXDCL this should be documented. */ - if (indirectmatch > 0) { if (matchelt != NULL) *matchelt = e; @@ -449,7 +519,6 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, * A negative indirect match may have set *matchelt, but we don't * want it set when we return. */ - if (matchelt != NULL) *matchelt = NULL; @@ -519,17 +588,15 @@ initialize_action(void) { */ static void is_insecure(isc_prefix_t *prefix, void **data) { - isc_boolean_t secure; - int bitlen, family; + int bitlen, family, off; bitlen = prefix->bitlen; family = prefix->family; /* Negated entries are always secure. */ - secure = * (isc_boolean_t *)data[ISC_IS6(family)]; - if (!secure) { + off = ISC_RADIX_OFF(prefix); + if (data[off] != NULL && * (isc_boolean_t *) data[off]) return; - } /* If loopback prefix found, return */ switch (family) { @@ -628,6 +695,7 @@ dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) { env->match_mapped = ISC_FALSE; #ifdef HAVE_GEOIP env->geoip = NULL; + env->geoip_use_ecs = ISC_FALSE; #endif return (ISC_R_SUCCESS); @@ -644,6 +712,9 @@ dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s) { dns_acl_detach(&t->localnets); dns_acl_attach(s->localnets, &t->localnets); t->match_mapped = s->match_mapped; +#ifdef HAVE_GEOIP + t->geoip_use_ecs = s->geoip_use_ecs; +#endif } void diff --git a/lib/dns/geoip.c b/lib/dns/geoip.c index 291b0d05e9..42109fedcb 100644 --- a/lib/dns/geoip.c +++ b/lib/dns/geoip.c @@ -72,6 +72,7 @@ typedef struct geoip_state { unsigned int family; isc_uint32_t ipnum; geoipv6_t ipnum6; + isc_uint8_t scope; GeoIPRecord *record; GeoIPRegion *region; const char *text; @@ -157,7 +158,7 @@ clean_state(geoip_state_t *state) { static isc_result_t set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6, - dns_geoip_subtype_t subtype, GeoIPRecord *record, + isc_uint8_t scope, dns_geoip_subtype_t subtype, GeoIPRecord *record, GeoIPRegion *region, char *name, const char *text, int id) { isc_result_t result; @@ -198,6 +199,7 @@ set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6, state->family = family; state->subtype = subtype; + state->scope = scope; state->record = record; state->region = region; state->name = name; @@ -232,10 +234,12 @@ get_state(void) { static const char * country_lookup(GeoIP *db, dns_geoip_subtype_t subtype, unsigned int family, - isc_uint32_t ipnum, const geoipv6_t *ipnum6) + isc_uint32_t ipnum, const geoipv6_t *ipnum6, + isc_uint8_t *scope) { geoip_state_t *prev_state = NULL; const char *text = NULL; + GeoIPLookup gl; REQUIRE(db != NULL); @@ -253,42 +257,55 @@ country_lookup(GeoIP *db, dns_geoip_subtype_t subtype, ((prev_state->family == AF_INET && prev_state->ipnum == ipnum) || (prev_state->family == AF_INET6 && ipnum6 != NULL && memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0))) + { text = prev_state->text; + if (scope != NULL) + *scope = prev_state->scope; + } if (text == NULL) { switch (subtype) { case dns_geoip_country_code: if (family == AF_INET) - text = GeoIP_country_code_by_ipnum(db, ipnum); + text = GeoIP_country_code_by_ipnum_gl(db, + ipnum, &gl); #ifdef HAVE_GEOIP_V6 else - text = GeoIP_country_code_by_ipnum_v6(db, - *ipnum6); + text = GeoIP_country_code_by_ipnum_v6_gl(db, + *ipnum6, &gl); #endif break; case dns_geoip_country_code3: if (family == AF_INET) - text = GeoIP_country_code3_by_ipnum(db, ipnum); + text = GeoIP_country_code3_by_ipnum_gl(db, + ipnum, &gl); #ifdef HAVE_GEOIP_V6 else - text = GeoIP_country_code3_by_ipnum_v6(db, - *ipnum6); + text = GeoIP_country_code3_by_ipnum_v6_gl(db, + *ipnum6, &gl); #endif break; case dns_geoip_country_name: if (family == AF_INET) - text = GeoIP_country_name_by_ipnum(db, ipnum); + text = GeoIP_country_name_by_ipnum_gl(db, + ipnum, &gl); #ifdef HAVE_GEOIP_V6 else - text = GeoIP_country_name_by_ipnum_v6(db, - *ipnum6); + text = GeoIP_country_name_by_ipnum_v6_gl(db, + *ipnum6, &gl); #endif break; default: INSIST(0); } - set_state(family, ipnum, ipnum6, subtype, + if (text == NULL) + return (NULL); + + if (scope != NULL) + *scope = gl.netmask; + + set_state(family, ipnum, ipnum6, gl.netmask, subtype, NULL, NULL, NULL, text, 0); } @@ -377,7 +394,9 @@ is_city(dns_geoip_subtype_t subtype) { */ static GeoIPRecord * city_lookup(GeoIP *db, dns_geoip_subtype_t subtype, - unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6) + unsigned int family, isc_uint32_t ipnum, + const geoipv6_t *ipnum6, + isc_uint8_t *scope) { GeoIPRecord *record = NULL; geoip_state_t *prev_state = NULL; @@ -397,7 +416,11 @@ city_lookup(GeoIP *db, dns_geoip_subtype_t subtype, ((prev_state->family == AF_INET && prev_state->ipnum == ipnum) || (prev_state->family == AF_INET6 && memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0))) + { record = prev_state->record; + if (scope != NULL) + *scope = record->netmask; + } if (record == NULL) { if (family == AF_INET) @@ -409,15 +432,17 @@ city_lookup(GeoIP *db, dns_geoip_subtype_t subtype, if (record == NULL) return (NULL); - set_state(family, ipnum, ipnum6, subtype, + if (scope != NULL) + *scope = record->netmask; + + set_state(family, ipnum, ipnum6, record->netmask, subtype, record, NULL, NULL, NULL, 0); } return (record); } -static char * -region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) { +static char * region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) { const char *s; char *deconst; @@ -459,9 +484,12 @@ is_region(dns_geoip_subtype_t subtype) { * outside the Region database. */ static GeoIPRegion * -region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { +region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, + isc_uint32_t ipnum, isc_uint8_t *scope) +{ GeoIPRegion *region = NULL; geoip_state_t *prev_state = NULL; + GeoIPLookup gl; REQUIRE(db != NULL); @@ -469,14 +497,21 @@ region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { if (prev_state != NULL && prev_state->ipnum == ipnum && is_region(prev_state->subtype)) + { region = prev_state->region; + if (scope != NULL) + *scope = prev_state->scope; + } if (region == NULL) { - region = GeoIP_region_by_ipnum(db, ipnum); + region = GeoIP_region_by_ipnum_gl(db, ipnum, &gl); if (region == NULL) return (NULL); - set_state(AF_INET, ipnum, NULL, + if (scope != NULL) + *scope = gl.netmask; + + set_state(AF_INET, ipnum, NULL, gl.netmask, subtype, NULL, region, NULL, NULL, 0); } @@ -489,9 +524,12 @@ region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { * or was for a search of a different subtype. */ static char * -name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { +name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, + isc_uint32_t ipnum, isc_uint8_t *scope) +{ char *name = NULL; geoip_state_t *prev_state = NULL; + GeoIPLookup gl; REQUIRE(db != NULL); @@ -499,14 +537,21 @@ name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { if (prev_state != NULL && prev_state->ipnum == ipnum && prev_state->subtype == subtype) + { name = prev_state->name; + if (scope != NULL) + *scope = prev_state->scope; + } if (name == NULL) { - name = GeoIP_name_by_ipnum(db, ipnum); + name = GeoIP_name_by_ipnum_gl(db, ipnum, &gl); if (name == NULL) return (NULL); - set_state(AF_INET, ipnum, NULL, + if (scope != NULL) + *scope = gl.netmask; + + set_state(AF_INET, ipnum, NULL, gl.netmask, subtype, NULL, NULL, name, NULL, 0); } @@ -519,9 +564,12 @@ name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { * different subtype. */ static int -netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { +netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, + isc_uint32_t ipnum, isc_uint8_t *scope) +{ geoip_state_t *prev_state = NULL; isc_boolean_t found = ISC_FALSE; + GeoIPLookup gl; int id = -1; REQUIRE(db != NULL); @@ -531,12 +579,20 @@ netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { if (prev_state != NULL && prev_state->ipnum == ipnum && prev_state->subtype == subtype) { id = prev_state->id; + if (scope != NULL) + *scope = prev_state->scope; found = ISC_TRUE; } if (!found) { - id = GeoIP_id_by_ipnum(db, ipnum); - set_state(AF_INET, ipnum, NULL, + id = GeoIP_id_by_ipnum_gl(db, ipnum, &gl); + if (id == 0) + return (0); + + if (scope != NULL) + *scope = gl.netmask; + + set_state(AF_INET, ipnum, NULL, gl.netmask, subtype, NULL, NULL, NULL, NULL, id); } @@ -599,7 +655,7 @@ fix_subtype(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip, #endif /* HAVE_GEOIP */ isc_boolean_t -dns_geoip_match(const isc_netaddr_t *reqaddr, +dns_geoip_match(const isc_netaddr_t *reqaddr, isc_uint8_t *scope, const dns_geoip_databases_t *geoip, const dns_geoip_elem_t *elt) { @@ -662,7 +718,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, INSIST(elt->as_string != NULL); - cs = country_lookup(db, subtype, family, ipnum, ipnum6); + cs = country_lookup(db, subtype, family, ipnum, ipnum6, scope); if (cs != NULL && strncasecmp(elt->as_string, cs, maxlen) == 0) return (ISC_TRUE); break; @@ -682,7 +738,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (db == NULL) return (ISC_FALSE); - record = city_lookup(db, subtype, family, ipnum, ipnum6); + record = city_lookup(db, subtype, family, + ipnum, ipnum6, scope); if (record == NULL) break; @@ -697,7 +754,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (db == NULL) return (ISC_FALSE); - record = city_lookup(db, subtype, family, ipnum, ipnum6); + record = city_lookup(db, subtype, family, + ipnum, ipnum6, scope); if (record == NULL) break; @@ -710,7 +768,8 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (db == NULL) return (ISC_FALSE); - record = city_lookup(db, subtype, family, ipnum, ipnum6); + record = city_lookup(db, subtype, family, + ipnum, ipnum6, scope); if (record == NULL) break; @@ -731,7 +790,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (family == AF_INET6) return (ISC_FALSE); - region = region_lookup(geoip->region, subtype, ipnum); + region = region_lookup(geoip->region, subtype, ipnum, scope); if (region == NULL) break; @@ -765,9 +824,22 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (family == AF_INET6) return (ISC_FALSE); - s = name_lookup(db, subtype, ipnum); - if (s != NULL && strcasecmp(elt->as_string, s) == 0) - return (ISC_TRUE); + s = name_lookup(db, subtype, ipnum, scope); + if (s != NULL) { + size_t l; + if (strcasecmp(elt->as_string, s) == 0) + return (ISC_TRUE); + if (subtype != dns_geoip_as_asnum) + break; + /* + * Just check if the ASNNNN value matches. + */ + l = strlen(elt->as_string); + if (l > 0U && strchr(elt->as_string, ' ') == NULL && + strncasecmp(elt->as_string, s, l) == 0 && + s[l] == ' ') + return (ISC_TRUE); + } break; case dns_geoip_netspeed_id: @@ -777,7 +849,7 @@ dns_geoip_match(const isc_netaddr_t *reqaddr, if (family == AF_INET6) return (ISC_FALSE); - id = netspeed_lookup(geoip->netspeed, subtype, ipnum); + id = netspeed_lookup(geoip->netspeed, subtype, ipnum, scope); if (id == elt->as_int) return (ISC_TRUE); break; diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h index ebcc6c7910..b2860e55bd 100644 --- a/lib/dns/include/dns/acl.h +++ b/lib/dns/include/dns/acl.h @@ -103,6 +103,7 @@ struct dns_aclenv { isc_boolean_t match_mapped; #ifdef HAVE_GEOIP dns_geoip_databases_t *geoip; + isc_boolean_t geoip_use_ecs; #endif }; @@ -212,12 +213,28 @@ dns_acl_match(const isc_netaddr_t *reqaddr, const dns_aclenv_t *env, int *match, const dns_aclelement_t **matchelt); + +isc_result_t +dns_acl_match2(const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, + const isc_netaddr_t *ecs, + isc_uint8_t ecslen, + isc_uint8_t *scope, + const dns_acl_t *acl, + const dns_aclenv_t *env, + int *match, + const dns_aclelement_t **matchelt); /*%< * General, low-level ACL matching. This is expected to * be useful even for weird stuff like the topology and sortlist statements. * * Match the address 'reqaddr', and optionally the key name 'reqsigner', - * against 'acl'. 'reqsigner' may be NULL. + * and optionally the client prefix 'ecs' of length 'ecslen' + * (reported via EDNS client subnet option) against 'acl'. + * + * 'reqsigner' and 'ecs' may be NULL. If an ACL matches against 'ecs' + * and 'ecslen', then 'scope' will be set to indicate the netmask that + * matched. * * If there is a match, '*match' will be set to an integer whose absolute * value corresponds to the order in which the matching value was inserted @@ -244,6 +261,16 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_aclelement_t *e, const dns_aclenv_t *env, const dns_aclelement_t **matchelt); + +isc_boolean_t +dns_aclelement_match2(const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, + const isc_netaddr_t *ecs, + isc_uint8_t ecslen, + isc_uint8_t *scope, + const dns_aclelement_t *e, + const dns_aclenv_t *env, + const dns_aclelement_t **matchelt); /*%< * Like dns_acl_match, but matches against the single ACL element 'e' * rather than a complete ACL, and returns ISC_TRUE iff it matched. diff --git a/lib/dns/include/dns/geoip.h b/lib/dns/include/dns/geoip.h index 35a4036a12..a656783223 100644 --- a/lib/dns/include/dns/geoip.h +++ b/lib/dns/include/dns/geoip.h @@ -108,7 +108,7 @@ typedef struct dns_geoip_databases { ISC_LANG_BEGINDECLS isc_boolean_t -dns_geoip_match(const isc_netaddr_t *reqaddr, +dns_geoip_match(const isc_netaddr_t *reqaddr, isc_uint8_t *scope, const dns_geoip_databases_t *geoip, const dns_geoip_elem_t *elt); diff --git a/lib/dns/include/dns/iptable.h b/lib/dns/include/dns/iptable.h index 2ce8e18124..512e73da06 100644 --- a/lib/dns/include/dns/iptable.h +++ b/lib/dns/include/dns/iptable.h @@ -51,6 +51,10 @@ dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target); isc_result_t dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, isc_uint16_t bitlen, isc_boolean_t pos); +isc_result_t +dns_iptable_addprefix2(dns_iptable_t *tab, isc_netaddr_t *addr, + isc_uint16_t bitlen, isc_boolean_t pos, + isc_boolean_t is_ecs); /* * Add an IP prefix to an existing IP table */ diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index de121c764d..183ecec755 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -112,7 +112,7 @@ #define DNS_OPT_SIT 65001 /*%< SIT opt code */ /*%< The number of EDNS options we know about. */ -#define DNS_EDNSOPTIONS 4 +#define DNS_EDNSOPTIONS 5 #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) diff --git a/lib/dns/iptable.c b/lib/dns/iptable.c index 701950533c..9413774947 100644 --- a/lib/dns/iptable.c +++ b/lib/dns/iptable.c @@ -14,8 +14,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: iptable.c,v 1.15 2009/02/18 23:47:48 tbox Exp $ */ - #include #include @@ -63,16 +61,24 @@ isc_boolean_t dns_iptable_pos = ISC_TRUE; isc_result_t dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, isc_uint16_t bitlen, isc_boolean_t pos) +{ + return(dns_iptable_addprefix2(tab, addr, bitlen, pos, ISC_FALSE)); +} + +isc_result_t +dns_iptable_addprefix2(dns_iptable_t *tab, isc_netaddr_t *addr, + isc_uint16_t bitlen, isc_boolean_t pos, + isc_boolean_t is_ecs) { isc_result_t result; isc_prefix_t pfx; isc_radix_node_t *node = NULL; - int family; + int i; INSIST(DNS_IPTABLE_VALID(tab)); INSIST(tab->radix); - NETADDR_TO_PREFIX_T(addr, pfx, bitlen); + NETADDR_TO_PREFIX_T(addr, pfx, bitlen, is_ecs); result = isc_radix_insert(tab->radix, &node, NULL, &pfx); if (result != ISC_R_SUCCESS) { @@ -81,28 +87,20 @@ dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, } /* If a node already contains data, don't overwrite it */ - family = pfx.family; - if (family == AF_UNSPEC) { + if (pfx.family == AF_UNSPEC) { /* "any" or "none" */ INSIST(pfx.bitlen == 0); - if (pos) { - if (node->data[0] == NULL) - node->data[0] = &dns_iptable_pos; - if (node->data[1] == NULL) - node->data[1] = &dns_iptable_pos; - } else { - if (node->data[0] == NULL) - node->data[0] = &dns_iptable_neg; - if (node->data[1] == NULL) - node->data[1] = &dns_iptable_neg; + for (i = 0; i < 4; i++) { + if (node->data[i] == NULL) + node->data[i] = pos ? &dns_iptable_pos + : &dns_iptable_neg; } } else { /* any other prefix */ - if (node->data[ISC_IS6(family)] == NULL) { - if (pos) - node->data[ISC_IS6(family)] = &dns_iptable_pos; - else - node->data[ISC_IS6(family)] = &dns_iptable_neg; + int offset = ISC_RADIX_OFF(&pfx); + if (node->data[offset] == NULL) { + node->data[offset] = pos ? &dns_iptable_pos + : &dns_iptable_neg; } } @@ -118,7 +116,7 @@ dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos) { isc_result_t result; isc_radix_node_t *node, *new_node; - int max_node = 0; + int i, max_node = 0; RADIX_WALK (source->radix->head, node) { new_node = NULL; @@ -135,20 +133,15 @@ dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos) * could be a security risk. To prevent this, we * just leave the negative nodes negative. */ - if (!pos) { - if (node->data[0] && - *(isc_boolean_t *) node->data[0] == ISC_TRUE) - new_node->data[0] = &dns_iptable_neg; - - if (node->data[1] && - *(isc_boolean_t *) node->data[1] == ISC_TRUE) - new_node->data[1] = &dns_iptable_neg; + for (i = 0; i < 4; i++) { + if (!pos) { + if (node->data[i] && + *(isc_boolean_t *) node->data[i]) + new_node->data[i] = &dns_iptable_neg; + } + if (node->node_num[i] > max_node) + max_node = node->node_num[i]; } - - if (node->node_num[0] > max_node) - max_node = node->node_num[0]; - if (node->node_num[1] > max_node) - max_node = node->node_num[1]; } RADIX_WALK_END; tab->radix->num_added_node += max_node; diff --git a/lib/dns/message.c b/lib/dns/message.c index 88c9239eb6..06b9068dd4 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id$ */ - /*! \file */ /*** diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index df35fa1f08..12a8fd567d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -80,11 +80,13 @@ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "res %p: %s", (r), (m)) -#define FCTXTRACE(m) isc_log_write(dns_lctx, \ +#define FCTXTRACE(m) \ + isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ - "fctx %p(%s): %s", fctx, fctx->info, (m)) + "fctx %p(%s): %s", \ + fctx, fctx->info, (m)) #define FCTXTRACE2(m1, m2) \ isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ @@ -92,6 +94,22 @@ ISC_LOG_DEBUG(3), \ "fctx %p(%s): %s %s", \ fctx, fctx->info, (m1), (m2)) +#define FCTXTRACE3(m, res) \ + isc_log_write(dns_lctx, \ + DNS_LOGCATEGORY_RESOLVER, \ + DNS_LOGMODULE_RESOLVER, \ + ISC_LOG_DEBUG(3), \ + "fctx %p(%s): [result: %s] %s", \ + fctx, fctx->info, \ + isc_result_totext(res), (m)) +#define FCTXTRACE4(m1, m2, res) \ + isc_log_write(dns_lctx, \ + DNS_LOGCATEGORY_RESOLVER, \ + DNS_LOGMODULE_RESOLVER, \ + ISC_LOG_DEBUG(3), \ + "fctx %p(%s): [result: %s] %s %s", \ + fctx, fctx->info, \ + isc_result_totext(res), (m1), (m2)) #define FTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ @@ -1268,6 +1286,9 @@ process_sendevent(resquery_t *query, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNREFUSED: + FCTXTRACE3("query canceled in sendevent(): " + "no route to host; no response", + sevent->result); /* * No route to remote. @@ -1279,6 +1300,10 @@ process_sendevent(resquery_t *query, isc_event_t *event) { break; default: + FCTXTRACE3("query canceled in sendevent() due to " + "unexpected event result; responding", + sevent->result); + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); break; } @@ -2359,6 +2384,9 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { isc_interval_set(&interval, 20, 0); result = fctx_startidletimer(query->fctx, &interval); if (result != ISC_R_SUCCESS) { + FCTXTRACE("query canceled: idle timer failed; " + "responding"); + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); fctx_done(fctx, result, __LINE__); break; @@ -2395,6 +2423,9 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { result = resquery_send(query); if (result != ISC_R_SUCCESS) { + FCTXTRACE("query canceled: " + "resquery_send() failed; responding"); + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); fctx_done(fctx, result, __LINE__); } @@ -2406,6 +2437,10 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNECTIONRESET: + FCTXTRACE3("query canceled in connected(): " + "no route to host; no response", + sevent->result); + /* * No route to remote. */ @@ -2415,6 +2450,10 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { break; default: + FCTXTRACE3("query canceled in connected() due to " + "unexpected event result; responding", + sevent->result); + isc_socket_detach(&query->tcpsocket); fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); break; @@ -2495,11 +2534,12 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); dns_adb_destroyfind(&find); - if (want_try) + if (want_try) { fctx_try(fctx, ISC_TRUE, ISC_FALSE); - else if (want_done) + } else if (want_done) { + FCTXTRACE("fetch failed in finddone(); return ISC_R_FAILURE"); fctx_done(fctx, ISC_R_FAILURE, __LINE__); - else if (destroy) { + } else if (destroy) { fctx_destroy(fctx); if (bucket_empty) empty_bucket(res); @@ -3479,6 +3519,7 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) { fctx->timeouts++; fctx->timeout = ISC_TRUE; + /* * We could cancel the running queries here, or we could let * them keep going. Since we normally use separate sockets for @@ -3490,10 +3531,13 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) { */ query = ISC_LIST_HEAD(fctx->queries); if (query != NULL && - isc_time_compare(&tevent->due, &query->start) >= 0) { + isc_time_compare(&tevent->due, &query->start) >= 0) + { + FCTXTRACE("query timed out; no response"); fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); } fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; + /* * Our timer has triggered. Reestablish the fctx lifetime * timer. @@ -3777,7 +3821,6 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, unsigned int findoptions = 0; char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; - dns_name_t suffix; isc_mem_t *mctx; /* @@ -3789,6 +3832,11 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, fctx = isc_mem_get(mctx, sizeof(*fctx)); if (fctx == NULL) return (ISC_R_NOMEMORY); + + /* + * Make fctx->info point to a copy of a formatted string + * "name/type". + */ dns_name_format(name, buf, sizeof(buf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); strcat(buf, "/"); /* checked */ @@ -3798,6 +3846,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, result = ISC_R_NOMEMORY; goto cleanup_fetch; } + FCTXTRACE("create"); dns_name_init(&fctx->name, NULL); result = dns_name_dup(name, mctx, &fctx->name); @@ -3870,10 +3919,12 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_forwarders_t *forwarders = NULL; unsigned int labels; dns_name_t *fwdname = name; + dns_name_t suffix; /* - * DS records are found in the parent server. - * Strip label to get the correct forwarder (if any). + * DS records are found in the parent server. Strip one + * leading label from the name (to be used in finding + * the forwarder). */ if (dns_rdatatype_atparent(fctx->type) && dns_name_countlabels(name) > 1) { @@ -3882,6 +3933,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_getlabelsequence(name, 1, labels - 1, &suffix); fwdname = &suffix; } + + /* Find the forwarder for this name. */ dns_fixedname_init(&fixed); domain = dns_fixedname_name(&fixed); result = dns_fwdtable_find2(fctx->res->view->fwdtable, fwdname, @@ -7170,6 +7223,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if (fctx->res->exiting) { result = ISC_R_SHUTTINGDOWN; + FCTXTRACE("resolver shutting down"); goto done; } @@ -7224,6 +7278,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { no_response = ISC_TRUE; } } + FCTXTRACE3("dispatcher failure", devent->result); goto done; } @@ -7231,14 +7286,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if (query->tsig != NULL) { result = dns_message_setquerytsig(message, query->tsig); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + FCTXTRACE3("unable to set query tsig", result); goto done; + } } if (query->tsigkey) { result = dns_message_settsigkey(message, query->tsigkey); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + FCTXTRACE3("unable to set tsig key", result); goto done; + } } if ((options & DNS_FETCHOPT_TCP) == 0) { @@ -7250,6 +7309,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } result = dns_message_parse(message, &devent->buffer, 0); if (result != ISC_R_SUCCESS) { + FCTXTRACE3("message failed to parse", result); switch (result) { case ISC_R_UNEXPECTEDEND: if (!message->question_ok || @@ -7338,6 +7398,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ resend = ISC_TRUE; /* XXXMPA log it */ + FCTXTRACE("bad sit"); goto done; } #endif @@ -7348,8 +7409,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * returns success anyway. */ result = dns_message_checksig(message, fctx->res->view); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + FCTXTRACE3("signature check failed", result); goto done; + } /* * The dispatcher should ensure we only get responses with QR set. @@ -7453,6 +7516,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { options |= DNS_FETCHOPT_TCP; resend = ISC_TRUE; } + FCTXTRACE3("message truncated", result); goto done; } @@ -7463,6 +7527,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* XXXRTH Log */ broken_server = DNS_R_UNEXPECTEDOPCODE; keep_trying = ISC_TRUE; + FCTXTRACE("invalid message opcode"); goto done; } @@ -7497,6 +7562,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if (message->rcode != dns_rcode_noerror && message->rcode != dns_rcode_nxdomain) { + isc_buffer_t b; + char code[64]; #ifdef ISC_PLATFORM_USESIT unsigned char sit[64]; @@ -7623,6 +7690,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) { INSIST(broken_server != ISC_R_SUCCESS); keep_trying = ISC_TRUE; } + + isc_buffer_init(&b, code, sizeof(code) - 1); + dns_rcode_totext(fctx->rmessage->rcode, &b); + code[isc_buffer_usedlength(&b)] = '\0'; + FCTXTRACE2("remote server broken: returned ", code); goto done; } @@ -7634,6 +7706,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* XXXRTH Log */ if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; + FCTXTRACE3("response did not match question", result); goto done; } @@ -7654,6 +7727,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_result_totext(result)); broken_server = DNS_R_LAME; keep_trying = ISC_TRUE; + FCTXTRACE("lame server"); goto done; } @@ -7706,22 +7780,32 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 || ISFORWARDER(query->addrinfo)) + { result = answer_response(fctx); - else if (iscname(fctx) && + if (result != ISC_R_SUCCESS) + FCTXTRACE3("answer_response (AA/fwd)", result); + } else if (iscname(fctx) && fctx->type != dns_rdatatype_any && - fctx->type != dns_rdatatype_cname) { + fctx->type != dns_rdatatype_cname) + { /* * A BIND8 server could return a non-authoritative * answer when a CNAME is followed. We should treat * it as a valid answer. */ result = answer_response(fctx); + if (result != ISC_R_SUCCESS) + FCTXTRACE3("answer_response (!ANY/!CNAME)", + result); } else if (fctx->type != dns_rdatatype_ns && !betterreferral(fctx)) { /* * Lame response !!!. */ result = answer_response(fctx); + if (result != ISC_R_SUCCESS) + FCTXTRACE("answer_response (!NS)"); + FCTXTRACE3("answer_response (!NS)", result); } else { if (fctx->type == dns_rdatatype_ns) { /* @@ -7734,6 +7818,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ result = noanswer_response(fctx, NULL, LOOK_FOR_NS_IN_ANSWER); + if (result != ISC_R_SUCCESS) + FCTXTRACE3("noanswer_response (NS)", + result); } else { /* * Some other servers may still somehow include @@ -7749,6 +7836,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ result = noanswer_response(fctx, NULL, LOOK_FOR_GLUE_IN_ANSWER); + if (result != ISC_R_SUCCESS) + FCTXTRACE3("noanswer_response", result); } if (result != DNS_R_DELEGATION) { /* @@ -7813,6 +7902,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; + FCTXTRACE3("noanswer_response", result); goto done; } } else { @@ -7822,6 +7912,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* XXXRTH Log */ broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; + FCTXTRACE("broken server: unexpected rcode"); goto done; } @@ -7836,8 +7927,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if (WANTCACHE(fctx)) { result = cache_message(fctx, query->addrinfo, now); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + FCTXTRACE3("cache_message complete", result); goto done; + } } /* @@ -7855,6 +7948,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Cache any negative cache entries in the message. */ result = ncache_message(fctx, query->addrinfo, covers, now); + if (result != ISC_R_SUCCESS) + FCTXTRACE3("ncache_message complete", result); } done: @@ -7864,6 +7959,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ addrinfo = query->addrinfo; + FCTXTRACE4("query canceled in response(); ", + no_response ? "no response" : "responding", + result); + /* * Cancel the query. * @@ -8616,6 +8715,10 @@ log_fetch(dns_name_t *name, dns_rdatatype_t type) { char typebuf[DNS_RDATATYPE_FORMATSIZE]; int level = ISC_LOG_DEBUG(1); + /* + * If there's no chance of logging it, don't render (format) the + * name and RDATA type (further below), and return early. + */ if (! isc_log_wouldlog(dns_lctx, level)) return; @@ -9022,6 +9125,11 @@ dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name) { unsigned int i; dns_badcache_t *bad, *prev, *next; + /* + * Drop all entries that match the name, and also all expired + * entries from the badcache. + */ + REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); @@ -9066,6 +9174,8 @@ dns_resolver_flushbadnames(dns_resolver_t *resolver, dns_name_t *name) { isc_time_t now; isc_result_t result; + /* Drop all expired entries from the badcache. */ + REQUIRE(VALID_RESOLVER(resolver)); REQUIRE(name != NULL); @@ -9105,6 +9215,13 @@ resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) { dns_badcache_t **new, *bad, *next; unsigned int i; + /* + * The number of buckets in the hashtable is modified in this + * function. Afterwards, all the entries are remapped into the + * corresponding new slot. Rehashing (hash computation) is + * unnecessary as the hash values had been saved. + */ + if (grow) newsize = resolver->badhash * 2 + 1; else @@ -9115,6 +9232,13 @@ resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) { if (new == NULL) return; memset(new, 0, sizeof(*resolver->badcache) * newsize); + + /* + * Because the hashtable implements a simple modulus mapping + * from hash to bucket (no extendible hashing is used), every + * name in the hashtable has to be remapped to its new slot. + * Entries that have expired (time) are dropped. + */ for (i = 0; i < resolver->badhash; i++) { for (bad = resolver->badcache[i]; bad != NULL; bad = next) { next = bad->next; @@ -9143,6 +9267,18 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, unsigned int i, hashval; dns_badcache_t *bad, *prev, *next; + /* + * The badcache is implemented as a hashtable keyed on the name, + * and each bucket slot points to a linked list (separate + * chaining). + * + * To avoid long list chains, if the number of entries in the + * hashtable goes over number-of-buckets * 8, the + * number-of-buckets is doubled. Similarly, if the number of + * entries goes below number-of-buckets * 2, the number-of-buckets + * is halved. See resizehash(). + */ + REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); @@ -9167,6 +9303,7 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, next = bad->next; if (bad->type == type && dns_name_equal(name, &bad->name)) break; + /* Drop expired entries when walking the chain. */ if (isc_time_compare(&bad->expire, &now) < 0) { if (prev == NULL) resolver->badcache[i] = bad->next; @@ -9179,6 +9316,12 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, prev = bad; } if (bad == NULL) { + /* + * Insert the name into the badcache hashtable at the + * head of the linked list at the appropriate slot. The + * name data follows right after the allocation for the + * linked list node. + */ isc_buffer_t buffer; bad = isc_mem_get(resolver->mctx, sizeof(*bad) + name->length); if (bad == NULL) @@ -9337,6 +9480,12 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, isc_result_t result; dns_rbtnode_t *node = NULL; + /* + * Whether an algorithm is disabled (or not) is stored in a + * per-name bitfield that is stored as the node data of an + * RBT. + */ + REQUIRE(VALID_RESOLVER(resolver)); if (alg > 255) return (ISC_R_RANGE); @@ -9358,7 +9507,17 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { algorithms = node->data; + /* + * If algorithms is set, algorithms[0] contains its + * length. + */ if (algorithms == NULL || len > *algorithms) { + /* + * If no bitfield exists in the node data, or if + * it is not long enough, allocate a new + * bitfield and copy the old (smaller) bitfield + * into it if one exists. + */ new = isc_mem_get(resolver->mctx, len); if (new == NULL) { result = ISC_R_NOMEMORY; @@ -9368,8 +9527,10 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, if (algorithms != NULL) memmove(new, algorithms, *algorithms); new[len-1] |= mask; + /* new[0] should contain the length of new. */ *new = len; node->data = new; + /* Free the older bitfield. */ if (algorithms != NULL) isc_mem_put(resolver->mctx, algorithms, *algorithms); @@ -9451,6 +9612,11 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name, isc_result_t result; dns_rbtnode_t *node = NULL; + /* + * Whether a digest is disabled (or not) is stored in a per-name + * bitfield that is stored as the node data of an RBT. + */ + REQUIRE(VALID_RESOLVER(resolver)); if (digest_type > 255) return (ISC_R_RANGE); @@ -9472,7 +9638,14 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name, if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { digests = node->data; + /* If digests is set, digests[0] contains its length. */ if (digests == NULL || len > *digests) { + /* + * If no bitfield exists in the node data, or if + * it is not long enough, allocate a new + * bitfield and copy the old (smaller) bitfield + * into it if one exists. + */ new = isc_mem_get(resolver->mctx, len); if (new == NULL) { result = ISC_R_NOMEMORY; @@ -9482,8 +9655,10 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, dns_name_t *name, if (digests != NULL) memmove(new, digests, *digests); new[len-1] |= mask; + /* new[0] should contain the length of new. */ *new = len; node->data = new; + /* Free the older bitfield. */ if (digests != NULL) isc_mem_put(resolver->mctx, digests, *digests); diff --git a/lib/dns/tests/geoip_test.c b/lib/dns/tests/geoip_test.c index a39ba727b4..60994d2ce9 100644 --- a/lib/dns/tests/geoip_test.c +++ b/lib/dns/tests/geoip_test.c @@ -136,8 +136,8 @@ load_geoip(const char *dir) { } static isc_boolean_t -do_lookup_string(const char *addr, dns_geoip_subtype_t subtype, - const char *string) +do_lookup_string(const char *addr, isc_uint8_t *scope, + dns_geoip_subtype_t subtype, const char *string) { dns_geoip_elem_t elt; struct in_addr in4; @@ -149,12 +149,12 @@ do_lookup_string(const char *addr, dns_geoip_subtype_t subtype, elt.subtype = subtype; strcpy(elt.as_string, string); - return (dns_geoip_match(&na, &geoip, &elt)); + return (dns_geoip_match(&na, scope, &geoip, &elt)); } static isc_boolean_t -do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype, - const char *string) +do_lookup_string_v6(const char *addr, isc_uint8_t *scope, + dns_geoip_subtype_t subtype, const char *string) { dns_geoip_elem_t elt; struct in6_addr in6; @@ -166,11 +166,13 @@ do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype, elt.subtype = subtype; strcpy(elt.as_string, string); - return (dns_geoip_match(&na, &geoip, &elt)); + return (dns_geoip_match(&na, scope, &geoip, &elt)); } static isc_boolean_t -do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) { +do_lookup_int(const char *addr, isc_uint8_t *scope, + dns_geoip_subtype_t subtype, int id) +{ dns_geoip_elem_t elt; struct in_addr in4; isc_netaddr_t na; @@ -181,7 +183,7 @@ do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) { elt.subtype = subtype; elt.as_int = id; - return (dns_geoip_match(&na, &geoip, &elt)); + return (dns_geoip_match(&na, scope, &geoip, &elt)); } /* @@ -196,6 +198,7 @@ ATF_TC_HEAD(country, tc) { ATF_TC_BODY(country, tc) { isc_result_t result; isc_boolean_t match; + isc_uint8_t scope; UNUSED(tc); @@ -210,16 +213,30 @@ ATF_TC_BODY(country, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU"); + match = do_lookup_string("10.53.0.1", &scope, + dns_geoip_country_code, "AU"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 32); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", &scope, dns_geoip_country_code3, "AUS"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 32); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", &scope, dns_geoip_country_name, "Australia"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 32); + + match = do_lookup_string("192.0.2.128", &scope, + dns_geoip_country_code, "O1"); + ATF_CHECK(match); + ATF_CHECK_EQ(scope, 24); + + match = do_lookup_string("192.0.2.128", &scope, + dns_geoip_country_name, "Other"); + ATF_CHECK(match); + ATF_CHECK_EQ(scope, 24); dns_test_end(); } @@ -232,6 +249,7 @@ ATF_TC_HEAD(country_v6, tc) { ATF_TC_BODY(country_v6, tc) { isc_result_t result; isc_boolean_t match; + isc_uint8_t scope; UNUSED(tc); @@ -246,17 +264,20 @@ ATF_TC_BODY(country_v6, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope, dns_geoip_country_code, "AU"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 128); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope, dns_geoip_country_code3, "AUS"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 128); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", &scope, dns_geoip_country_name, "Australia"); ATF_CHECK(match); + ATF_CHECK_EQ(scope, 128); dns_test_end(); } @@ -283,42 +304,42 @@ ATF_TC_BODY(city, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_continentcode, "NA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_countrycode, "US"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_countrycode3, "USA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_countryname, "United States"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_region, "CA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_regionname, "California"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_name, "Redwood City"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_city_postalcode, "94063"); ATF_CHECK(match); - match = do_lookup_int("10.53.0.1", dns_geoip_city_areacode, 650); + match = do_lookup_int("10.53.0.1", NULL, dns_geoip_city_areacode, 650); ATF_CHECK(match); - match = do_lookup_int("10.53.0.1", dns_geoip_city_metrocode, 807); + match = do_lookup_int("10.53.0.1", NULL, dns_geoip_city_metrocode, 807); ATF_CHECK(match); dns_test_end(); @@ -346,36 +367,36 @@ ATF_TC_BODY(city_v6, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_continentcode, "NA"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_countrycode, "US"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_countrycode3, "USA"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_countryname, "United States"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_region, "CA"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_regionname, "California"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_name, "Redwood City"); ATF_CHECK(match); - match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", + match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", NULL, dns_geoip_city_postalcode, "94063"); ATF_CHECK(match); @@ -405,15 +426,15 @@ ATF_TC_BODY(region, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_region_code, "CA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_region_name, "California"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.1", + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_region_countrycode, "US"); ATF_CHECK(match); @@ -447,30 +468,30 @@ ATF_TC_BODY(best, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode, "US"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode3, "USA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countryname, "United States"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_regionname, "Virginia"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_region, "VA"); ATF_CHECK(match); GeoIP_delete(geoip.city_v4); geoip.city_v4 = NULL; - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode, "AU"); ATF_CHECK(match); @@ -478,26 +499,26 @@ ATF_TC_BODY(best, tc) { * Note, region doesn't support code3 or countryname, so * the next two would be answered from the country database instead */ - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode3, "CAN"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countryname, "Canada"); ATF_CHECK(match); GeoIP_delete(geoip.region); geoip.region = NULL; - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode, "CA"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countrycode3, "CAN"); ATF_CHECK(match); - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_countryname, "Canada"); ATF_CHECK(match); @@ -528,7 +549,7 @@ ATF_TC_BODY(asnum, tc) { } - match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum, + match = do_lookup_string("10.53.0.3", NULL, dns_geoip_as_asnum, "AS100003 Three Network Labs"); ATF_CHECK(match); @@ -557,7 +578,7 @@ ATF_TC_BODY(isp, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.1", dns_geoip_isp_name, + match = do_lookup_string("10.53.0.1", NULL, dns_geoip_isp_name, "One Systems, Inc."); ATF_CHECK(match); @@ -586,7 +607,7 @@ ATF_TC_BODY(org, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.2", dns_geoip_org_name, + match = do_lookup_string("10.53.0.2", NULL, dns_geoip_org_name, "Two Technology Ltd."); ATF_CHECK(match); @@ -615,7 +636,7 @@ ATF_TC_BODY(domain, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_string("10.53.0.4", + match = do_lookup_string("10.53.0.4", NULL, dns_geoip_domain_name, "four.com"); ATF_CHECK(match); @@ -644,16 +665,16 @@ ATF_TC_BODY(netspeed, tc) { atf_tc_skip("Database not available"); } - match = do_lookup_int("10.53.0.1", dns_geoip_netspeed_id, 0); + match = do_lookup_int("10.53.0.1", NULL, dns_geoip_netspeed_id, 0); ATF_CHECK(match); - match = do_lookup_int("10.53.0.2", dns_geoip_netspeed_id, 1); + match = do_lookup_int("10.53.0.2", NULL, dns_geoip_netspeed_id, 1); ATF_CHECK(match); - match = do_lookup_int("10.53.0.3", dns_geoip_netspeed_id, 2); + match = do_lookup_int("10.53.0.3", NULL, dns_geoip_netspeed_id, 2); ATF_CHECK(match); - match = do_lookup_int("10.53.0.4", dns_geoip_netspeed_id, 3); + match = do_lookup_int("10.53.0.4", NULL, dns_geoip_netspeed_id, 3); ATF_CHECK(match); dns_test_end(); diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index 862b2b03fe..422f21c3ee 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -25,9 +25,11 @@ dns_acl_isany dns_acl_isinsecure dns_acl_isnone dns_acl_match +dns_acl_match2 dns_acl_merge dns_acl_none dns_aclelement_match +dns_aclelement_match2 dns_aclenv_copy dns_aclenv_destroy dns_aclenv_init diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h index 1c1887f1d0..4d0b3b08f1 100644 --- a/lib/isc/include/isc/radix.h +++ b/lib/isc/include/isc/radix.h @@ -14,8 +14,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: radix.h,v 1.13 2008/12/01 23:47:45 tbox Exp $ */ - /* * This source was adapted from MRT's RCS Ids: * Id: radix.h,v 1.6 1999/08/03 03:32:53 masaki Exp @@ -34,7 +32,7 @@ #ifndef _RADIX_H #define _RADIX_H -#define NETADDR_TO_PREFIX_T(na,pt,bits) \ +#define NETADDR_TO_PREFIX_T(na,pt,bits,isecs) \ do { \ memset(&(pt), 0, sizeof(pt)); \ if((na) != NULL) { \ @@ -50,6 +48,7 @@ (pt).family = AF_UNSPEC; \ (pt).bitlen = 0; \ } \ + (pt).ecs = isecs; \ isc_refcount_init(&(pt).refcount, 0); \ } while(0) @@ -57,6 +56,7 @@ typedef struct isc_prefix { isc_mem_t *mctx; unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */ unsigned int bitlen; /* 0 for "any" */ + isc_boolean_t ecs; /* ISC_TRUE for an EDNS client subnet address */ isc_refcount_t refcount; union { struct in_addr sin; @@ -81,23 +81,32 @@ typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **); * return the one that was added first. * * An IPv4 prefix and an IPv6 prefix may share a radix tree node if they - * have the same length and bit pattern (e.g., 127/8 and 7f::/8). To - * disambiguate between them, node_num and data are two-element arrays; - * node_num[0] and data[0] are used for IPv4 addresses, node_num[1] - * and data[1] for IPv6 addresses. The only exception is a prefix of - * 0/0 (aka "any" or "none"), which is always stored as IPv4 but matches - * IPv6 addresses too. + * have the same length and bit pattern (e.g., 127/8 and 7f::/8). Also, + * a node that matches a client address may also match an EDNS client + * subnet address. To disambiguate between these, node_num and data + * are four-element arrays; + * + * - node_num[0] and data[0] are used for IPv4 client addresses + * - node_num[1] and data[1] for IPv4 client subnet addresses + * - node_num[2] and data[2] are used for IPv6 client addresses + * - node_num[3] and data[3] for IPv6 client subnet addresses + * + * A prefix of 0/0 (aka "any" or "none"), is always stored as IPv4, + * but matches IPv6 addresses too, as well as all client subnet + * addresses. */ -#define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0) +#define ISC_RADIX_OFF(p) \ + ((((p)->family == AF_INET6) ? 1 : 0) + ((p)->ecs ? 2 : 0)) + typedef struct isc_radix_node { isc_mem_t *mctx; isc_uint32_t bit; /* bit length of the prefix */ isc_prefix_t *prefix; /* who we are in radix tree */ struct isc_radix_node *l, *r; /* left and right children */ struct isc_radix_node *parent; /* may be used */ - void *data[2]; /* pointers to IPv4 and IPV6 data */ - int node_num[2]; /* which node this was in the tree, + void *data[4]; /* pointers to IPv4 and IPV6 data */ + int node_num[4]; /* which node this was in the tree, or -1 for glue nodes */ } isc_radix_node_t; diff --git a/lib/isc/radix.c b/lib/isc/radix.c index df26615fa9..47e13b7856 100644 --- a/lib/isc/radix.c +++ b/lib/isc/radix.c @@ -70,6 +70,7 @@ _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest, } prefix->family = family; + prefix->ecs = ISC_FALSE; prefix->mctx = NULL; isc_mem_attach(mctx, &prefix->mctx); @@ -182,12 +183,13 @@ _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) { if (Xrn->prefix != NULL) { _deref_prefix(Xrn->prefix); - if (func != NULL && (Xrn->data[0] != NULL || - Xrn->data[1] != NULL)) + if (func != NULL) func(Xrn->data); } else { INSIST(Xrn->data[0] == NULL && - Xrn->data[1] == NULL); + Xrn->data[1] == NULL && + Xrn->data[2] == NULL && + Xrn->data[3] == NULL); } isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn)); @@ -242,8 +244,7 @@ isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, isc_radix_node_t *stack[RADIX_MAXBITS + 1]; u_char *addr; isc_uint32_t bitlen; - int tfamily = -1; - int cnt = 0; + int toff = -1, cnt = 0; REQUIRE(radix != NULL); REQUIRE(prefix != NULL); @@ -281,13 +282,15 @@ isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, if (_comp_with_mask(isc_prefix_tochar(node->prefix), isc_prefix_tochar(prefix), - node->prefix->bitlen)) { - if (node->node_num[ISC_IS6(prefix->family)] != -1 && - ((*target == NULL) || - (*target)->node_num[ISC_IS6(tfamily)] > - node->node_num[ISC_IS6(prefix->family)])) { + node->prefix->bitlen)) + { + int off = ISC_RADIX_OFF(prefix); + if (node->node_num[off] != -1 && + ((*target == NULL) || + (*target)->node_num[toff] > node->node_num[off])) + { *target = node; - tfamily = prefix->family; + toff = off; } } } @@ -327,7 +330,8 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, if (node == NULL) return (ISC_R_NOMEMORY); node->bit = bitlen; - node->node_num[0] = node->node_num[1] = -1; + for (i = 0; i < 4; i++) + node->node_num[i] = -1; node->prefix = NULL; result = _ref_prefix(radix->mctx, &node->prefix, prefix); if (result != ISC_R_SUCCESS) { @@ -346,25 +350,24 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, * added to num_added_node at the end of * the merge operation--we don't do it here. */ - if (source->node_num[0] != -1) - node->node_num[0] = radix->num_added_node + - source->node_num[0]; - if (source->node_num[1] != -1) - node->node_num[1] = radix->num_added_node + - source->node_num[1]; - node->data[0] = source->data[0]; - node->data[1] = source->data[1]; + for (i = 0; i < 4; i++) { + if (source->node_num[i] != -1) + node->node_num[i] = + radix->num_added_node + + source->node_num[i]; + node->data[i] = source->data[i]; + } } else { + int next = ++radix->num_added_node; if (fam == AF_UNSPEC) { /* "any" or "none" */ - node->node_num[0] = node->node_num[1] = - ++radix->num_added_node; + for (i = 0; i < 4; i++) + node->node_num[i] = next; } else { - node->node_num[ISC_IS6(fam)] = - ++radix->num_added_node; + node->node_num[ISC_RADIX_OFF(prefix)] = next; } - node->data[0] = NULL; - node->data[1] = NULL; + + memset(node->data, 0, sizeof(node->data)); } radix->head = node; radix->num_active_node++; @@ -426,37 +429,33 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, if (node->prefix != NULL) { /* Set node_num only if it hasn't been set before */ if (source != NULL) { - /* Merging node */ - if (node->node_num[0] == -1 && - source->node_num[0] != -1) { - node->node_num[0] = - radix->num_added_node + - source->node_num[0]; - node->data[0] = source->data[0]; - } - if (node->node_num[1] == -1 && - source->node_num[0] != -1) { - node->node_num[1] = - radix->num_added_node + - source->node_num[1]; - node->data[1] = source->data[1]; + /* Merging nodes */ + for (i = 0; i < 4; i++) { + if (node->node_num[i] == -1 && + source->node_num[i] != -1) { + node->node_num[i] = + radix->num_added_node + + source->node_num[i]; + node->data[i] = source->data[i]; + } } } else { if (fam == AF_UNSPEC) { /* "any" or "none" */ int next = radix->num_added_node + 1; - if (node->node_num[0] == -1) { - node->node_num[0] = next; - radix->num_added_node = next; - } - if (node->node_num[1] == -1) { - node->node_num[1] = next; - radix->num_added_node = next; + for (i = 0; i < 4; i++) { + if (node->node_num[i] == -1) { + node->node_num[i] = + next; + radix->num_added_node = + next; + } } } else { - if (node->node_num[ISC_IS6(fam)] == -1) - node->node_num[ISC_IS6(fam)] - = ++radix->num_added_node; + int off = ISC_RADIX_OFF(prefix); + if (node->node_num[off] == -1) + node->node_num[off] = + ++radix->num_added_node; } } *target = node; @@ -468,27 +467,27 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, return (result); } INSIST(node->data[0] == NULL && node->node_num[0] == -1 && - node->data[1] == NULL && node->node_num[1] == -1); + node->data[1] == NULL && node->node_num[1] == -1 && + node->data[2] == NULL && node->node_num[2] == -1 && + node->data[3] == NULL && node->node_num[3] == -1); if (source != NULL) { /* Merging node */ - if (source->node_num[0] != -1) { - node->node_num[0] = radix->num_added_node + - source->node_num[0]; - node->data[0] = source->data[0]; - } - if (source->node_num[1] != -1) { - node->node_num[1] = radix->num_added_node + - source->node_num[1]; - node->data[1] = source->data[1]; + for (i = 0; i < 4; i++) { + int cur = radix->num_added_node; + if (source->node_num[i] != -1) { + node->node_num[i] = + source->node_num[i] + cur; + node->data[i] = source->data[i]; + } } } else { + int next = ++radix->num_added_node; if (fam == AF_UNSPEC) { /* "any" or "none" */ - node->node_num[0] = node->node_num[1] = - ++radix->num_added_node; + for (i = 0; i < 4; i++) + node->node_num[i] = next; } else { - node->node_num[ISC_IS6(fam)] = - ++radix->num_added_node; + node->node_num[ISC_RADIX_OFF(prefix)] = next; } } *target = node; @@ -518,30 +517,30 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, } new_node->parent = NULL; new_node->l = new_node->r = NULL; - new_node->node_num[0] = new_node->node_num[1] = -1; + for (i = 0; i < 4; i++) + new_node->node_num[i] = -1; radix->num_active_node++; if (source != NULL) { /* Merging node */ - if (source->node_num[0] != -1) - new_node->node_num[0] = radix->num_added_node + - source->node_num[0]; - if (source->node_num[1] != -1) - new_node->node_num[1] = radix->num_added_node + - source->node_num[1]; - new_node->data[0] = source->data[0]; - new_node->data[1] = source->data[1]; + for (i = 0; i < 4; i++) { + int cur = radix->num_added_node; + if (source->node_num[i] != -1) { + new_node->node_num[i] = + source->node_num[i] + cur; + new_node->data[i] = source->data[i]; + } + } } else { + int next = ++radix->num_added_node; if (fam == AF_UNSPEC) { /* "any" or "none" */ - new_node->node_num[0] = new_node->node_num[1] = - ++radix->num_added_node; + for (i = 0; i < 4; i++) + new_node->node_num[i] = next; } else { - new_node->node_num[ISC_IS6(fam)] = - ++radix->num_added_node; + new_node->node_num[ISC_RADIX_OFF(prefix)] = next; } - new_node->data[0] = NULL; - new_node->data[1] = NULL; + memset(new_node->data, 0, sizeof(new_node->data)); } if (node->bit == differ_bit) { @@ -583,8 +582,10 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, glue->bit = differ_bit; glue->prefix = NULL; glue->parent = node->parent; - glue->data[0] = glue->data[1] = NULL; - glue->node_num[0] = glue->node_num[1] = -1; + for (i = 0; i < 4; i++) { + glue->data[i] = NULL; + glue->node_num[i] = -1; + } radix->num_active_node++; if (differ_bit < radix->maxbits && BIT_TEST(addr[differ_bit>>3], 0x80 >> (differ_bit & 07))) { @@ -627,7 +628,7 @@ isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) { _deref_prefix(node->prefix); node->prefix = NULL; - node->data[0] = node->data[1] = NULL; + memset(node->data, 0, sizeof(node->data)); return; } diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c index 76f6ad4a9a..03dd4401ec 100644 --- a/lib/isccfg/aclconf.c +++ b/lib/isccfg/aclconf.c @@ -482,6 +482,7 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, const char *stype, *search; dns_geoip_subtype_t subtype; dns_aclelement_t de; + size_t len; REQUIRE(dep != NULL); @@ -493,35 +494,52 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype")); search = cfg_obj_asstring(cfg_tuple_get(obj, "search")); + len = strlen(search); - if (strcasecmp(stype, "country") == 0 && strlen(search) == 2) { + if (len == 0) { + cfg_obj_log(obj, lctx, ISC_LOG_ERROR, + "zero-length geoip search field"); + return (ISC_R_FAILURE); + } + + if (strcasecmp(stype, "country") == 0 && len == 2) { /* Two-letter country code */ subtype = dns_geoip_countrycode; - strncpy(de.geoip_elem.as_string, search, 2); - } else if (strcasecmp(stype, "country") == 0 && strlen(search) == 3) { + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "country") == 0 && len == 3) { /* Three-letter country code */ subtype = dns_geoip_countrycode3; - strncpy(de.geoip_elem.as_string, search, 3); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "country") == 0) { /* Country name */ subtype = dns_geoip_countryname; - strncpy(de.geoip_elem.as_string, search, 255); - } else if (strcasecmp(stype, "region") == 0 && strlen(search) == 2) { + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "region") == 0 && len == 2) { /* Two-letter region code */ subtype = dns_geoip_region; - strncpy(de.geoip_elem.as_string, search, 2); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "region") == 0) { /* Region name */ subtype = dns_geoip_regionname; - strncpy(de.geoip_elem.as_string, search, 255); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "city") == 0) { /* City name */ subtype = dns_geoip_city_name; - strncpy(de.geoip_elem.as_string, search, 255); - } else if (strcasecmp(stype, "postal") == 0 && strlen(search) < 7) { + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "postal") == 0 && len < 7) { subtype = dns_geoip_city_postalcode; - strncpy(de.geoip_elem.as_string, search, 6); - de.geoip_elem.as_string[6] = '\0'; + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "postal") == 0) { + cfg_obj_log(obj, lctx, ISC_LOG_ERROR, + "geoiop postal code (%s) too long", search); + return (ISC_R_FAILURE); } else if (strcasecmp(stype, "metro") == 0) { subtype = dns_geoip_city_metrocode; de.geoip_elem.as_int = atoi(search); @@ -530,23 +548,33 @@ parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, de.geoip_elem.as_int = atoi(search); } else if (strcasecmp(stype, "tz") == 0) { subtype = dns_geoip_city_timezonecode; - strncpy(de.geoip_elem.as_string, search, 255); - } else if (strcasecmp(stype, "continent") == 0 && strlen(search) == 2) { + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "continent") == 0 && len == 2) { /* Two-letter continent code */ subtype = dns_geoip_city_continentcode; - strncpy(de.geoip_elem.as_string, search, 2); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); + } else if (strcasecmp(stype, "continent") == 0) { + cfg_obj_log(obj, lctx, ISC_LOG_ERROR, + "geoiop continent code (%s) too long", search); + return (ISC_R_FAILURE); } else if (strcasecmp(stype, "isp") == 0) { subtype = dns_geoip_isp_name; - strncpy(de.geoip_elem.as_string, search, 255); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "asnum") == 0) { subtype = dns_geoip_as_asnum; - strncpy(de.geoip_elem.as_string, search, 255); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "org") == 0) { subtype = dns_geoip_org_name; - strncpy(de.geoip_elem.as_string, search, 255); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "domain") == 0) { subtype = dns_geoip_domain_name; - strncpy(de.geoip_elem.as_string, search, 255); + strlcpy(de.geoip_elem.as_string, search, + sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "netspeed") == 0) { subtype = dns_geoip_netspeed_id; de.geoip_elem.as_int = atoi(search); @@ -668,6 +696,7 @@ cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx, /* Network prefix */ isc_netaddr_t addr; unsigned int bitlen; + isc_boolean_t setpos, setecs; cfg_obj_asnetprefix(ce, &addr, &bitlen); if (family != 0 && family != addr.family) { @@ -685,8 +714,10 @@ cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx, * If nesting ACLs (nest_level != 0), we negate * the nestedacl element, not the iptable entry. */ - result = dns_iptable_addprefix(iptab, &addr, bitlen, - ISC_TF(nest_level != 0 || !neg)); + setpos = ISC_TF(nest_level != 0 || !neg); + setecs = cfg_obj_istype(ce, &cfg_type_ecsprefix); + result = dns_iptable_addprefix2(iptab, &addr, bitlen, + setpos, setecs); if (result != ISC_R_SUCCESS) goto cleanup; diff --git a/lib/isccfg/include/isccfg/namedconf.h b/lib/isccfg/include/isccfg/namedconf.h index 507da06587..67cca35bbc 100644 --- a/lib/isccfg/include/isccfg/namedconf.h +++ b/lib/isccfg/include/isccfg/namedconf.h @@ -54,4 +54,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sessionkey; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref; /*%< A key reference, used as an ACL element */ +/*%< An EDNS client subnet address, used as an ACL element */ +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ecsprefix; + #endif /* ISCCFG_NAMEDCONF_H */ diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index f8b3bad316..03f4b01d51 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -950,9 +950,12 @@ options_clauses[] = { { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, #ifdef HAVE_GEOIP { "geoip-directory", &cfg_type_qstringornone, 0 }, + { "geoip-use-ecs", &cfg_type_boolean, 0 }, #else { "geoip-directory", &cfg_type_qstringornone, CFG_CLAUSEFLAG_NOTCONFIGURED }, + { "geoip-use-ecs", &cfg_type_qstringornone, + CFG_CLAUSEFLAG_NOTCONFIGURED }, #endif /* HAVE_GEOIP */ { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "heartbeat-interval", &cfg_type_uint32, 0 }, @@ -2281,6 +2284,16 @@ doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) { } #endif /* HAVE_GEOIP */ +/*% + * An EDNS client subnet address + */ + +static keyword_type_t ecs_kw = { "ecs", &cfg_type_netprefix }; +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ecsprefix = { + "edns_client_subnet", parse_keyvalue, print_keyvalue, doc_keyvalue, + &cfg_rep_netprefix, &ecs_kw +}; + /*% * A "controls" statement is represented as a map with the multivalued * "inet" and "unix" clauses. @@ -2570,6 +2583,9 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) if (pctx->token.type == isc_tokentype_string && (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) { CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret)); + } else if (pctx->token.type == isc_tokentype_string && + (strcasecmp(TOKEN_STRING(pctx), "ecs") == 0)) { + CHECK(cfg_parse_obj(pctx, &cfg_type_ecsprefix, ret)); } else if (pctx->token.type == isc_tokentype_string && (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) { #ifdef HAVE_GEOIP diff --git a/util/copyrights b/util/copyrights index d43244f545..a1cc91e696 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1313,10 +1313,11 @@ ./bin/tests/system/geoip/geoip.c C 2013 ./bin/tests/system/geoip/ns2/example.db.in ZONE 2013 ./bin/tests/system/geoip/ns2/named1.conf CONF-C 2013 -./bin/tests/system/geoip/ns2/named10.conf CONF-C 2013 +./bin/tests/system/geoip/ns2/named10.conf CONF-C 2014 ./bin/tests/system/geoip/ns2/named11.conf CONF-C 2013 -./bin/tests/system/geoip/ns2/named12.conf CONF-C 2014 +./bin/tests/system/geoip/ns2/named12.conf CONF-C 2013 ./bin/tests/system/geoip/ns2/named13.conf CONF-C 2014 +./bin/tests/system/geoip/ns2/named14.conf CONF-C 2014 ./bin/tests/system/geoip/ns2/named2.conf CONF-C 2013 ./bin/tests/system/geoip/ns2/named3.conf CONF-C 2013 ./bin/tests/system/geoip/ns2/named4.conf CONF-C 2013