From 67adc03ef81fb610f8df093b17f55275ee816754 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 22 Mar 2013 12:27:54 -0700 Subject: [PATCH] [master] add DSCP support 3535. [func] Add support for setting Differentiated Services Code Point (DSCP) values in named. Most configuration options which take a "port" option (e.g., listen-on, forwarders, also-notify, masters, notify-source, etc) can now also take a "dscp" option specifying a code point for use with outgoing traffic, if supported by the underlying OS. [RT #27596] --- CHANGES | 9 + bin/named/client.c | 41 +- bin/named/config.c | 154 ++++++- bin/named/include/named/client.h | 1 + bin/named/include/named/config.h | 17 +- bin/named/include/named/globals.h | 1 + bin/named/include/named/interfacemgr.h | 1 + bin/named/include/named/listenlist.h | 5 +- bin/named/interfacemgr.c | 52 ++- bin/named/listenlist.c | 7 +- bin/named/lwresd.c | 7 +- bin/named/main.c | 10 + bin/named/server.c | 128 ++++-- bin/named/zoneconf.c | 46 +- bin/tests/adb_test.c | 10 +- bin/tests/resolver/t_resolver.c | 6 +- bin/tests/system/checkconf/good.conf | 7 +- bin/tests/system/checkconf/range.conf | 28 ++ bin/tests/system/checkconf/tests.sh | 6 + bin/tests/system/conf.sh.in | 2 +- bin/tests/system/dnssec/ns4/named1.conf | 6 +- bin/tests/system/dnssec/ns4/named2.conf | 7 +- bin/tests/system/dscp/clean.sh | 2 + bin/tests/system/dscp/ns1/named.args | 1 + bin/tests/system/dscp/ns1/named.conf | 35 ++ bin/tests/system/dscp/ns1/root.db | 8 + bin/tests/system/dscp/ns2/named.args | 1 + bin/tests/system/dscp/ns2/named.conf | 36 ++ bin/tests/system/dscp/ns3/hint.db | 5 + bin/tests/system/dscp/ns3/named.args | 1 + bin/tests/system/dscp/ns3/named.conf | 34 ++ bin/tests/system/dscp/ns4/named.args | 1 + bin/tests/system/dscp/ns4/named.conf | 35 ++ bin/tests/system/dscp/ns4/root.db | 8 + bin/tests/system/dscp/ns5/named.args | 1 + bin/tests/system/dscp/ns5/named.conf | 37 ++ bin/tests/system/dscp/ns6/hint.db | 5 + bin/tests/system/dscp/ns6/named.args | 1 + bin/tests/system/dscp/ns6/named.conf | 34 ++ bin/tests/system/dscp/ns7/named.args | 1 + bin/tests/system/dscp/ns7/named.conf | 40 ++ bin/tests/system/dscp/tests.sh | 27 ++ bin/tests/system/nsupdate/ns1/named.conf | 6 +- bin/tests/system/nsupdate/ns2/named.conf | 6 +- bin/tests/system/nsupdate/ns3/named.conf | 6 +- bin/tests/system/resolver/ns1/named.conf | 6 +- bin/tests/system/resolver/ns4/named.conf | 6 +- bin/tests/system/resolver/ns5/named.conf | 6 +- bin/tests/system/resolver/ns6/named.conf | 6 +- bin/tests/system/resolver/ns7/named.conf | 6 +- doc/arm/Bv9ARM-book.xml | 122 +++--- doc/design/dscp | 133 ++++++ doc/misc/options | 175 ++++---- lib/bind9/check.c | 26 ++ lib/dns/adb.c | 1 + lib/dns/dispatch.c | 14 + lib/dns/forward.c | 83 +++- lib/dns/include/dns/adb.h | 4 +- lib/dns/include/dns/dispatch.h | 12 + lib/dns/include/dns/forward.h | 19 +- lib/dns/include/dns/peer.h | 20 + lib/dns/include/dns/request.h | 28 +- lib/dns/include/dns/resolver.h | 17 + lib/dns/include/dns/types.h | 1 + lib/dns/include/dns/xfrin.h | 8 + lib/dns/include/dns/zone.h | 117 +++++- lib/dns/peer.c | 54 +++ lib/dns/request.c | 84 +++- lib/dns/resolver.c | 89 +++- lib/dns/win32/libdns.def | 23 + lib/dns/xfrin.c | 27 +- lib/dns/zone.c | 305 ++++++++++++-- lib/isc/include/isc/namespace.h | 1 + lib/isc/include/isc/socket.h | 22 + lib/isc/include/isc/types.h | 1 + lib/isc/socket_api.c | 7 + lib/isc/tests/Makefile.in | 4 +- lib/isc/tests/isctest.c | 2 +- lib/isc/tests/socket_test.c | 512 ++++++++++++++++++++++- lib/isc/unix/include/isc/net.h | 15 + lib/isc/unix/net.c | 260 ++++++++++++ lib/isc/unix/socket.c | 270 +++++++++++- lib/isc/win32/include/isc/net.h | 14 + lib/isc/win32/libisc.def | 3 + lib/isc/win32/net.c | 5 + lib/isc/win32/socket.c | 56 ++- lib/isccfg/include/isccfg/cfg.h | 14 + lib/isccfg/include/isccfg/grammar.h | 9 + lib/isccfg/namedconf.c | 91 +++- lib/isccfg/parser.c | 78 +++- lib/isccfg/win32/libisccfg.def | 1 + 91 files changed, 3240 insertions(+), 399 deletions(-) create mode 100644 bin/tests/system/checkconf/range.conf create mode 100644 bin/tests/system/dscp/clean.sh create mode 100644 bin/tests/system/dscp/ns1/named.args create mode 100644 bin/tests/system/dscp/ns1/named.conf create mode 100644 bin/tests/system/dscp/ns1/root.db create mode 100644 bin/tests/system/dscp/ns2/named.args create mode 100644 bin/tests/system/dscp/ns2/named.conf create mode 100644 bin/tests/system/dscp/ns3/hint.db create mode 100644 bin/tests/system/dscp/ns3/named.args create mode 100644 bin/tests/system/dscp/ns3/named.conf create mode 100644 bin/tests/system/dscp/ns4/named.args create mode 100644 bin/tests/system/dscp/ns4/named.conf create mode 100644 bin/tests/system/dscp/ns4/root.db create mode 100644 bin/tests/system/dscp/ns5/named.args create mode 100644 bin/tests/system/dscp/ns5/named.conf create mode 100644 bin/tests/system/dscp/ns6/hint.db create mode 100644 bin/tests/system/dscp/ns6/named.args create mode 100644 bin/tests/system/dscp/ns6/named.conf create mode 100644 bin/tests/system/dscp/ns7/named.args create mode 100644 bin/tests/system/dscp/ns7/named.conf create mode 100644 bin/tests/system/dscp/tests.sh create mode 100644 doc/design/dscp diff --git a/CHANGES b/CHANGES index a94d624b64..83f6e74af2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +3536. [func] Add support for setting Differentiated Services Code + Point (DSCP) values in named. Most configuration + options which take a "port" option (e.g., + listen-on, forwarders, also-notify, masters, + notify-source, etc) can now also take a "dscp" + option specifying a code point for use with + outgoing traffic, if supported by the underlying + OS. [RT #27596] + 3535. [bug] Minor win32 cleanups. [RT #32962] 3534. [bug] Extra text after an embedded NULL was ignored when diff --git a/bin/named/client.c b/bin/named/client.c index 710c876b86..67403d07a4 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -827,6 +827,7 @@ client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { isc_netaddr_t netaddr; int match; unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE; + isc_dscp_t dispdscp = -1; if (TCP_CLIENT(client)) { socket = client->tcpsocket; @@ -852,6 +853,20 @@ client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { else pktinfo = NULL; + if (client->dispatch != NULL) { + dispdscp = dns_dispatch_getdscp(client->dispatch); + if (dispdscp != -1) + client->dscp = dispdscp; + } + + if (client->dscp == -1) { + client->sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; + client->sendevent->dscp = 0; + } else { + client->sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; + client->sendevent->dscp = client->dscp; + } + isc_buffer_usedregion(buffer, &r); CTRACE("sendto"); @@ -1533,6 +1548,13 @@ client_request(isc_task_t *task, isc_event_t *event) { client->peeraddr = sevent->address; client->peeraddr_valid = ISC_TRUE; } + if ((sevent->attributes & ISC_SOCKEVENTATTR_DSCP) != 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(90), + "received DSCP %d", sevent->dscp); + if (client->dscp == -1) + client->dscp = sevent->dscp; + } if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { client->attributes |= NS_CLIENTATTR_PKTINFO; client->pktinfo = sevent->pktinfo; @@ -2196,11 +2218,9 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { /* XXXRTH Hardwired constants */ - client->sendevent = (isc_socketevent_t *) - isc_event_allocate(client->mctx, client, - ISC_SOCKEVENT_SENDDONE, - client_senddone, client, - sizeof(isc_socketevent_t)); + client->sendevent = isc_socket_socketevent(client->mctx, client, + ISC_SOCKEVENT_SENDDONE, + client_senddone, client); if (client->sendevent == NULL) { result = ISC_R_NOMEMORY; goto cleanup_message; @@ -2212,11 +2232,9 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { goto cleanup_sendevent; } - client->recvevent = (isc_socketevent_t *) - isc_event_allocate(client->mctx, client, - ISC_SOCKEVENT_RECVDONE, - client_request, client, - sizeof(isc_socketevent_t)); + client->recvevent = isc_socket_socketevent(client->mctx, client, + ISC_SOCKEVENT_RECVDONE, + client_request, client); if (client->recvevent == NULL) { result = ISC_R_NOMEMORY; goto cleanup_recvbuf; @@ -2243,6 +2261,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { client->tcpbuf = NULL; client->opt = NULL; client->udpsize = 512; + client->dscp = -1; client->extflags = 0; client->ednsversion = -1; client->next = NULL; @@ -2737,6 +2756,8 @@ get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, client->state = NS_CLIENTSTATE_READY; INSIST(client->recursionquota == NULL); + client->dscp = ifp->dscp; + if (tcp) { client->attributes |= NS_CLIENTATTR_TCP; isc_socket_attach(ifp->tcpsocket, diff --git a/bin/named/config.c b/bin/named/config.c index bd1df75408..e423c00f4f 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -64,6 +64,7 @@ options {\n\ session-keyalg hmac-sha256;\n\ deallocate-on-exit true;\n\ # directory \n\ + dscp 0;\n\ dump-file \"named_dump.db\";\n\ fake-iquery no;\n\ has-old-clients false;\n\ @@ -279,7 +280,9 @@ ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) { } isc_result_t -ns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { +ns_config_get(cfg_obj_t const * const *maps, const char *name, + const cfg_obj_t **obj) +{ int i; for (i = 0;; i++) { @@ -402,17 +405,20 @@ ns_config_getzonetype(const cfg_obj_t *zonetypeobj) { isc_result_t ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, in_port_t defport, isc_mem_t *mctx, - isc_sockaddr_t **addrsp, isc_uint32_t *countp) + isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, + isc_uint32_t *countp) { int count, i = 0; const cfg_obj_t *addrlist; - const cfg_obj_t *portobj; + const cfg_obj_t *portobj, *dscpobj; const cfg_listelt_t *element; isc_sockaddr_t *addrs; in_port_t port; + isc_dscp_t dscp = -1, *dscps; isc_result_t result; INSIST(addrsp != NULL && *addrsp == NULL); + INSIST(dscpsp == NULL || *dscpsp == NULL); INSIST(countp != NULL); addrlist = cfg_tuple_get(list, "addresses"); @@ -435,6 +441,23 @@ ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, return (result); } + if (dscpsp != NULL) { + dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t)); + if (dscps == NULL) + return (ISC_R_NOMEMORY); + + dscpobj = cfg_tuple_get(list, "dscp"); + if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + } + addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); if (addrs == NULL) return (ISC_R_NOMEMORY); @@ -443,8 +466,17 @@ ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, element != NULL; element = cfg_list_next(element), i++) { + const cfg_obj_t *addr; INSIST(i < count); - addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element)); + addr = cfg_listelt_value(element); + addrs[i] = *cfg_obj_assockaddr(addr); + if (dscpsp != NULL) { + isc_dscp_t innerdscp; + innerdscp = cfg_obj_getdscp(addr); + if (innerdscp == -1) + innerdscp = dscp; + dscps[i] = innerdscp; + } if (isc_sockaddr_getport(&addrs[i]) == 0) isc_sockaddr_setport(&addrs[i], port); } @@ -453,17 +485,26 @@ ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, *addrsp = addrs; *countp = count; + if (dscpsp != NULL) + *dscpsp = dscps; + return (ISC_R_SUCCESS); } void ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, - isc_uint32_t count) + isc_dscp_t **dscpsp, isc_uint32_t count) { INSIST(addrsp != NULL && *addrsp != NULL); + INSIST(dscpsp == NULL || *dscpsp != NULL); isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); *addrsp = NULL; + + if (dscpsp != NULL) { + isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t)); + *dscpsp = NULL; + } } static isc_result_t @@ -497,32 +538,40 @@ get_masters_def(const cfg_obj_t *cctx, const char *name, isc_result_t ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_mem_t *mctx, isc_sockaddr_t **addrsp, - dns_name_t ***keysp, isc_uint32_t *countp) + isc_dscp_t **dscpsp, dns_name_t ***keysp, + isc_uint32_t *countp) { - isc_uint32_t addrcount = 0, keycount = 0, i = 0; + isc_uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0; isc_uint32_t listcount = 0, l = 0, j; isc_uint32_t stackcount = 0, pushed = 0; isc_result_t result; const cfg_listelt_t *element; const cfg_obj_t *addrlist; const cfg_obj_t *portobj; + const cfg_obj_t *dscpobj; in_port_t port; + isc_dscp_t dscp; dns_fixedname_t fname; isc_sockaddr_t *addrs = NULL; + isc_dscp_t *dscps = NULL; dns_name_t **keys = NULL; struct { const char *name; } *lists = NULL; struct { const cfg_listelt_t *element; in_port_t port; + isc_dscp_t dscp; } *stack = NULL; REQUIRE(addrsp != NULL && *addrsp == NULL); + REQUIRE(dscpsp != NULL && *dscpsp == NULL); REQUIRE(keysp != NULL && *keysp == NULL); REQUIRE(countp != NULL); newlist: addrlist = cfg_tuple_get(list, "addresses"); portobj = cfg_tuple_get(list, "port"); + dscpobj = cfg_tuple_get(list, "dscp"); + if (cfg_obj_isuint32(portobj)) { isc_uint32_t val = cfg_obj_asuint32(portobj); if (val > ISC_UINT16_MAX) { @@ -538,6 +587,20 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, goto cleanup; } + if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } else { + result = ns_config_getdscp(config, &dscp); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + result = ISC_R_NOMEMORY; element = cfg_list_first(addrlist); @@ -618,6 +681,7 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, */ stack[pushed].element = cfg_list_next(element); stack[pushed].port = port; + stack[pushed].dscp = dscp; pushed++; goto newlist; } @@ -639,6 +703,18 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, addrs = new; addrcount = newlen; + newsize = newlen * sizeof(isc_dscp_t); + oldsize = dscpcount * sizeof(isc_dscp_t); + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + if (dscpcount != 0) { + memcpy(new, dscps, oldsize); + isc_mem_put(mctx, dscps, oldsize); + } + dscps = new; + dscpcount = newlen; + newsize = newlen * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); new = isc_mem_get(mctx, newsize); @@ -655,6 +731,9 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, addrs[i] = *cfg_obj_assockaddr(addr); if (isc_sockaddr_getport(&addrs[i]) == 0) isc_sockaddr_setport(&addrs[i], port); + dscps[i] = cfg_obj_getdscp(addr); + if (dscps[i] == -1) + dscps[i] = dscp; keys[i] = NULL; i++; /* Increment here so that cleanup on error works. */ if (!cfg_obj_isstring(key)) @@ -681,6 +760,7 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, pushed--; element = stack[pushed].element; port = stack[pushed].port; + dscp = stack[pushed].dscp; goto resume; } if (i < addrcount) { @@ -700,6 +780,19 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, addrs = new; addrcount = i; + newsize = i * sizeof(isc_dscp_t); + oldsize = dscpcount * sizeof(isc_dscp_t); + if (i != 0) { + new = isc_mem_get(mctx, newsize); + if (new == NULL) + goto cleanup; + memcpy(new, dscps, newsize); + } else + new = NULL; + isc_mem_put(mctx, dscps, oldsize); + dscps = new; + dscpcount = i; + newsize = i * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); if (i != 0) { @@ -722,6 +815,7 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, INSIST(keycount == addrcount); *addrsp = addrs; + *dscpsp = dscps; *keysp = keys; *countp = addrcount; @@ -730,6 +824,8 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, cleanup: if (addrs != NULL) isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); + if (dscps != NULL) + isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t)); if (keys != NULL) { for (j = 0; j < i; j++) { if (keys[j] == NULL) @@ -749,14 +845,21 @@ ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, void ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, - dns_name_t ***keysp, isc_uint32_t count) + isc_dscp_t **dscpsp, dns_name_t ***keysp, + isc_uint32_t count) { unsigned int i; - dns_name_t **keys = *keysp; + dns_name_t **keys; - INSIST(addrsp != NULL && *addrsp != NULL); + REQUIRE(addrsp != NULL && *addrsp != NULL); + REQUIRE(dscpsp == NULL || *dscpsp != NULL); + REQUIRE(keysp != NULL && *keysp != NULL); + + keys = *keysp; isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t)); + if (dscpsp != NULL) + isc_mem_put(mctx, *dscpsp, count * sizeof(isc_dscp_t)); for (i = 0; i < count; i++) { if (keys[i] == NULL) continue; @@ -766,6 +869,8 @@ ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, } isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *)); *addrsp = NULL; + if (dscpsp != NULL) + *dscpsp = NULL; *keysp = NULL; } @@ -796,6 +901,35 @@ ns_config_getport(const cfg_obj_t *config, in_port_t *portp) { return (ISC_R_SUCCESS); } +isc_result_t +ns_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) { + const cfg_obj_t *maps[2]; + const cfg_obj_t *options = NULL; + const cfg_obj_t *dscpobj = NULL; + isc_result_t result; + int i; + + (void)cfg_map_get(config, "options", &options); + i = 0; + if (options != NULL) + maps[i++] = options; + maps[i] = NULL; + + result = ns_config_get(maps, "dscp", &dscpobj); + if (dscpobj == NULL) { + *dscpp = -1; + return (ISC_R_SUCCESS); + } + if (cfg_obj_asuint32(dscpobj) >= 64) { + cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, + "dscp '%u' out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + *dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + return (ISC_R_SUCCESS); +} + struct keyalgorithms { const char *str; enum { hmacnone, hmacmd5, hmacsha1, hmacsha224, diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index 483464d2f0..38cf14fd6d 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -141,6 +141,7 @@ struct ns_client { isc_boolean_t peeraddr_valid; isc_netaddr_t destaddr; struct in6_pktinfo pktinfo; + isc_dscp_t dscp; isc_event_t ctlevent; #ifdef ALLOW_FILTER_AAAA dns_aaaa_t filter_aaaa; diff --git a/bin/named/include/named/config.h b/bin/named/include/named/config.h index c16c800fe1..dd388c6aa6 100644 --- a/bin/named/include/named/config.h +++ b/bin/named/include/named/config.h @@ -31,7 +31,8 @@ isc_result_t ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf); isc_result_t -ns_config_get(const cfg_obj_t **maps, const char* name, const cfg_obj_t **obj); +ns_config_get(cfg_obj_t const * const *maps, const char* name, + const cfg_obj_t **obj); isc_result_t ns_checknames_get(const cfg_obj_t **maps, const char* name, @@ -54,20 +55,23 @@ ns_config_getzonetype(const cfg_obj_t *zonetypeobj); isc_result_t ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, in_port_t defport, isc_mem_t *mctx, - isc_sockaddr_t **addrsp, isc_uint32_t *countp); + isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, + isc_uint32_t *countp); void ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, - isc_uint32_t count); + isc_dscp_t **dscpsp, isc_uint32_t count); isc_result_t ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_mem_t *mctx, isc_sockaddr_t **addrsp, - dns_name_t ***keys, isc_uint32_t *countp); + isc_dscp_t **dscpp, dns_name_t ***keys, + isc_uint32_t *countp); void ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, - dns_name_t ***keys, isc_uint32_t count); + isc_dscp_t **dscpsp, dns_name_t ***keys, + isc_uint32_t count); isc_result_t ns_config_getport(const cfg_obj_t *config, in_port_t *portp); @@ -79,4 +83,7 @@ isc_result_t ns_config_getkeyalgorithm2(const char *str, dns_name_t **name, unsigned int *typep, isc_uint16_t *digestbits); +isc_result_t +ns_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp); + #endif /* NAMED_CONFIG_H */ diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index dddcdc98e1..dfa0647b90 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -72,6 +72,7 @@ EXTERN const char * ns_g_product INIT(PRODUCT); EXTERN const char * ns_g_srcid INIT(SRCID); EXTERN const char * ns_g_configargs INIT(CONFIGARGS); EXTERN in_port_t ns_g_port INIT(0); +EXTERN isc_dscp_t ns_g_dscp INIT(-1); EXTERN in_port_t lwresd_g_listenport INIT(0); EXTERN ns_server_t * ns_g_server INIT(NULL); diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h index 380dbedd76..014d8730e4 100644 --- a/bin/named/include/named/interfacemgr.h +++ b/bin/named/include/named/interfacemgr.h @@ -80,6 +80,7 @@ struct ns_interface { dns_dispatch_t * udpdispatch[MAX_UDP_DISPATCH]; /*%< UDP dispatchers. */ isc_socket_t * tcpsocket; /*%< TCP socket. */ + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ int ntcptarget; /*%< Desired number of concurrent TCP accepts */ int ntcpcurrent; /*%< Current ditto, locked */ diff --git a/bin/named/include/named/listenlist.h b/bin/named/include/named/listenlist.h index 9e65d5df3a..d6c2dbb909 100644 --- a/bin/named/include/named/listenlist.h +++ b/bin/named/include/named/listenlist.h @@ -46,6 +46,7 @@ typedef struct ns_listenlist ns_listenlist_t; struct ns_listenelt { isc_mem_t * mctx; in_port_t port; + isc_dscp_t dscp; /* -1 = not set, 0..63 */ dns_acl_t * acl; ISC_LINK(ns_listenelt_t) link; }; @@ -61,7 +62,7 @@ struct ns_listenlist { ***/ isc_result_t -ns_listenelt_create(isc_mem_t *mctx, in_port_t port, +ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, dns_acl_t *acl, ns_listenelt_t **target); /*% * Create a listen-on list element. @@ -92,7 +93,7 @@ ns_listenlist_detach(ns_listenlist_t **listp); */ isc_result_t -ns_listenlist_default(isc_mem_t *mctx, in_port_t port, +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, isc_boolean_t enabled, ns_listenlist_t **target); /*% * Create a listen-on list with default contents, matching diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c index 268e47d893..418107214c 100644 --- a/bin/named/interfacemgr.c +++ b/bin/named/interfacemgr.c @@ -234,6 +234,8 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, ifp->ntcpcurrent = 0; ifp->nudpdispatch = 0; + ifp->dscp = -1; + ISC_LINK_INIT(ifp, link); ns_interfacemgr_attach(mgr, &ifp->mgr); @@ -345,6 +347,10 @@ ns_interface_accepttcp(ns_interface_t *ifp) { isc_result_totext(result)); goto tcp_bind_failure; } + + if (ifp->dscp != -1) + isc_socket_dscp(ifp->tcpsocket, ifp->dscp); + result = isc_socket_listen(ifp->tcpsocket, ns_g_listen); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, @@ -381,7 +387,7 @@ ns_interface_accepttcp(ns_interface_t *ifp) { static isc_result_t ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ns_interface_t **ifpret, - isc_boolean_t accept_tcp) + isc_boolean_t accept_tcp, isc_dscp_t dscp) { isc_result_t result; ns_interface_t *ifp = NULL; @@ -391,6 +397,8 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, if (result != ISC_R_SUCCESS) return (result); + ifp->dscp = dscp; + result = ns_interface_listenudp(ifp); if (result != ISC_R_SUCCESS) goto cleanup_interface; @@ -627,6 +635,7 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, ns_interface_t *ifp; isc_boolean_t log_explicit = ISC_FALSE; isc_boolean_t dolistenon; + char sabuf[ISC_SOCKADDR_FORMATSIZE]; if (ext_listen != NULL) adjusting = ISC_TRUE; @@ -682,6 +691,18 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, ifp = find_matching_interface(mgr, &listen_addr); if (ifp != NULL) { ifp->generation = mgr->generation; + if (le->dscp != -1 && ifp->dscp == -1) + ifp->dscp = le->dscp; + else if (le->dscp != ifp->dscp) { + isc_sockaddr_format(&listen_addr, + sabuf, + sizeof(sabuf)); + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_WARNING, + "%s: conflicting DSCP " + "values, using %d", + sabuf, ifp->dscp); + } } else { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, @@ -690,7 +711,8 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, le->port); result = ns_interface_setup(mgr, &listen_addr, "", &ifp, - ISC_TRUE); + ISC_TRUE, + le->dscp); if (result == ISC_R_SUCCESS) ifp->flags |= NS_INTERFACEFLAG_ANYADDR; else @@ -843,9 +865,19 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, ifp = find_matching_interface(mgr, &listen_sockaddr); if (ifp != NULL) { ifp->generation = mgr->generation; + if (le->dscp != -1 && ifp->dscp == -1) + ifp->dscp = le->dscp; + else if (le->dscp != ifp->dscp) { + isc_sockaddr_format(&listen_addr, + sabuf, + sizeof(sabuf)); + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_WARNING, + "%s: conflicting DSCP " + "values, using %d", + sabuf, ifp->dscp); + } } else { - char sabuf[ISC_SOCKADDR_FORMATSIZE]; - if (adjusting == ISC_FALSE && ipv6_wildcard == ISC_TRUE) continue; @@ -875,12 +907,12 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, interface.name, sabuf); result = ns_interface_setup(mgr, - &listen_sockaddr, - interface.name, - &ifp, - (adjusting == ISC_TRUE) ? - ISC_FALSE : - ISC_TRUE); + &listen_sockaddr, + interface.name, + &ifp, + (adjusting == ISC_TRUE) ? + ISC_FALSE : ISC_TRUE, + le->dscp); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, diff --git a/bin/named/listenlist.c b/bin/named/listenlist.c index 513fe9c70b..691f83c832 100644 --- a/bin/named/listenlist.c +++ b/bin/named/listenlist.c @@ -32,7 +32,7 @@ static void destroy(ns_listenlist_t *list); isc_result_t -ns_listenelt_create(isc_mem_t *mctx, in_port_t port, +ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, dns_acl_t *acl, ns_listenelt_t **target) { ns_listenelt_t *elt = NULL; @@ -43,6 +43,7 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, elt->mctx = mctx; ISC_LINK_INIT(elt, link); elt->port = port; + elt->dscp = dscp; elt->acl = acl; *target = elt; return (ISC_R_SUCCESS); @@ -100,7 +101,7 @@ ns_listenlist_detach(ns_listenlist_t **listp) { } isc_result_t -ns_listenlist_default(isc_mem_t *mctx, in_port_t port, +ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, isc_boolean_t enabled, ns_listenlist_t **target) { isc_result_t result; @@ -116,7 +117,7 @@ ns_listenlist_default(isc_mem_t *mctx, in_port_t port, if (result != ISC_R_SUCCESS) goto cleanup; - result = ns_listenelt_create(mctx, port, acl, &elt); + result = ns_listenelt_create(mctx, port, dscp, acl, &elt); if (result != ISC_R_SUCCESS) goto cleanup_acl; diff --git a/bin/named/lwresd.c b/bin/named/lwresd.c index 7ee2196364..d1d1f76de5 100644 --- a/bin/named/lwresd.c +++ b/bin/named/lwresd.c @@ -812,11 +812,12 @@ ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) { isc_uint32_t i; CHECK(ns_config_getiplist(config, listenerslist, - port, mctx, &addrs, &count)); + port, mctx, &addrs, NULL, + &count)); for (i = 0; i < count; i++) CHECK(configure_listener(&addrs[i], lwresd, mctx, &newlisteners)); - ns_config_putiplist(mctx, &addrs, count); + ns_config_putiplist(mctx, &addrs, NULL, count); } ns_lwdmanager_detach(&lwresd); } @@ -845,7 +846,7 @@ ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) { ISC_LIST_APPENDLIST(listeners, newlisteners, link); if (addrs != NULL) - ns_config_putiplist(mctx, &addrs, count); + ns_config_putiplist(mctx, &addrs, NULL, count); if (lwresd != NULL) ns_lwdmanager_detach(&lwresd); diff --git a/bin/named/main.c b/bin/named/main.c index 785c65e758..fdabbbe0c4 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -97,6 +97,8 @@ #define BACKTRACE_MAXFRAME 128 #endif +extern int isc_dscp_check_value; + static isc_boolean_t want_stats = ISC_FALSE; static char program_name[ISC_DIR_NAMEMAX] = "named"; static char absolute_conffile[ISC_DIR_PATHMAX]; @@ -510,10 +512,15 @@ parse_command_line(int argc, char *argv[]) { break; case 'T': /* NOT DOCUMENTED */ /* + * force the server to behave (or misbehave) in + * specified ways for testing purposes. + * * clienttest: make clients single shot with their * own memory context. * delay=xxxx: delay client responses by xxxx ms to * simulate remote servers. + * dscp=x: check that dscp values are as + * expected and assert otherwise. */ if (!strcmp(isc_commandline_argument, "clienttest")) ns_g_clienttest = ISC_TRUE; @@ -539,6 +546,9 @@ parse_command_line(int argc, char *argv[]) { ns_g_nosyslog = ISC_TRUE; else if (!strcmp(isc_commandline_argument, "nonearest")) ns_g_nonearest = ISC_TRUE; + else if (!strncmp(isc_commandline_argument, "dscp=", 5)) + isc_dscp_check_value = + atoi(isc_commandline_argument + 5); else fprintf(stderr, "unknown -T flag '%s\n", isc_commandline_argument); diff --git a/bin/named/server.c b/bin/named/server.c index 84ac1b8900..a5c20350d1 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -936,8 +936,8 @@ mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) { * Get a dispatch appropriate for the resolver of a given view. */ static isc_result_t -get_view_querysource_dispatch(const cfg_obj_t **maps, - int af, dns_dispatch_t **dispatchp, +get_view_querysource_dispatch(const cfg_obj_t **maps, int af, + dns_dispatch_t **dispatchp, isc_dscp_t *dscpp, isc_boolean_t is_firstview) { isc_result_t result = ISC_R_FAILURE; @@ -946,6 +946,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, unsigned int attrs, attrmask; const cfg_obj_t *obj = NULL; unsigned int maxdispatchbuffers; + isc_dscp_t dscp = -1; switch (af) { case AF_INET: @@ -963,6 +964,10 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, sa = *(cfg_obj_assockaddr(obj)); INSIST(isc_sockaddr_pf(&sa) == af); + dscp = cfg_obj_getdscp(obj); + if (dscp != -1 && dscpp != NULL) + *dscpp = dscp; + /* * If we don't support this address family, we're done! */ @@ -1206,6 +1211,9 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { if (obj != NULL) { result = dns_peer_settransfersource(peer, cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj)); if (result != ISC_R_SUCCESS) goto cleanup; ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); @@ -1219,6 +1227,9 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { if (obj != NULL) { result = dns_peer_setnotifysource(peer, cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj)); if (result != ISC_R_SUCCESS) goto cleanup; ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); @@ -1232,6 +1243,9 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { if (obj != NULL) { result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj)); if (result != ISC_R_SUCCESS) goto cleanup; ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); @@ -2082,6 +2096,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, unsigned int query_timeout, ndisp; struct cfg_context *nzctx; isc_boolean_t old_rpz_ok = ISC_FALSE; + isc_dscp_t dscp4 = -1, dscp6 = -1; REQUIRE(DNS_VIEW_VALID(view)); @@ -2652,10 +2667,10 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, * * XXXRTH Hardwired number of tasks. */ - CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, + CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, &dscp4, ISC_TF(ISC_LIST_PREV(view, link) == NULL))); - CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, + CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, &dscp6, ISC_TF(ISC_LIST_PREV(view, link) == NULL))); if (dispatch4 == NULL && dispatch6 == NULL) { @@ -2681,6 +2696,15 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, resopts, ns_g_dispatchmgr, dispatch4, dispatch6)); + if (dscp4 == -1) + dscp4 = ns_g_dscp; + if (dscp6 == -1) + dscp6 = ns_g_dscp; + if (dscp4 != -1) + dns_resolver_setquerydscp4(view->resolver, dscp4); + if (dscp6 != -1) + dns_resolver_setquerydscp6(view->resolver, dscp6); + /* * Set the ADB cache size to 1/8th of the max-cache-size or * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared. @@ -3589,16 +3613,17 @@ static isc_result_t configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) { - const cfg_obj_t *portobj; + const cfg_obj_t *portobj, *dscpobj; const cfg_obj_t *faddresses; const cfg_listelt_t *element; dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; - isc_sockaddrlist_t addresses; - isc_sockaddr_t *sa; + dns_forwarderlist_t fwdlist; + dns_forwarder_t *fwd; isc_result_t result; in_port_t port; + isc_dscp_t dscp = -1; - ISC_LIST_INIT(addresses); + ISC_LIST_INIT(fwdlist); /* * Determine which port to send forwarded requests to. @@ -3621,6 +3646,22 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, } } + /* + * DSCP value for forwarded requests. + */ + dscpobj = cfg_tuple_get(forwarders, "dscp"); + if (!cfg_obj_isuint32(dscpobj)) + dscp = ns_g_dscp; + else { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + faddresses = NULL; if (forwarders != NULL) faddresses = cfg_tuple_get(forwarders, "addresses"); @@ -3630,19 +3671,22 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, element = cfg_list_next(element)) { const cfg_obj_t *forwarder = cfg_listelt_value(element); - sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); - if (sa == NULL) { + fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t)); + if (fwd == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - *sa = *cfg_obj_assockaddr(forwarder); - if (isc_sockaddr_getport(sa) == 0) - isc_sockaddr_setport(sa, port); - ISC_LINK_INIT(sa, link); - ISC_LIST_APPEND(addresses, sa, link); + fwd->addr = *cfg_obj_assockaddr(forwarder); + if (isc_sockaddr_getport(&fwd->addr) == 0) + isc_sockaddr_setport(&fwd->addr, port); + fwd->dscp = cfg_obj_getdscp(forwarder); + if (fwd->dscp == -1) + fwd->dscp = dscp; + ISC_LINK_INIT(fwd, link); + ISC_LIST_APPEND(fwdlist, fwd, link); } - if (ISC_LIST_EMPTY(addresses)) { + if (ISC_LIST_EMPTY(fwdlist)) { if (forwardtype != NULL) cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, "no forwarders seen; disabling " @@ -3662,8 +3706,8 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, } } - result = dns_fwdtable_add(view->fwdtable, origin, &addresses, - fwdpolicy); + result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist, + fwdpolicy); if (result != ISC_R_SUCCESS) { char namebuf[DNS_NAME_FORMATSIZE]; dns_name_format(origin, namebuf, sizeof(namebuf)); @@ -3677,10 +3721,10 @@ configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, cleanup: - while (!ISC_LIST_EMPTY(addresses)) { - sa = ISC_LIST_HEAD(addresses); - ISC_LIST_UNLINK(addresses, sa, link); - isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); + while (!ISC_LIST_EMPTY(fwdlist)) { + fwd = ISC_LIST_HEAD(fwdlist); + ISC_LIST_UNLINK(fwdlist, fwd, link); + isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t)); } return (result); @@ -4275,7 +4319,7 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { static isc_result_t add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, - isc_boolean_t wcardport_ok) + isc_dscp_t dscp, isc_boolean_t wcardport_ok) { ns_listenelt_t *lelt = NULL; dns_acl_t *src_acl = NULL; @@ -4300,7 +4344,7 @@ add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr, goto clean; result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), - src_acl, &lelt); + dscp, src_acl, &lelt); if (result != ISC_R_SUCCESS) goto clean; ISC_LIST_APPEND(list->elts, lelt, link); @@ -4328,6 +4372,7 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { dns_view_t *view; dns_zone_t *zone, *next; isc_sockaddr_t addr, *addrp; + isc_dscp_t dscp; result = ns_listenlist_create(mctx, &list); if (result != ISC_R_SUCCESS) @@ -4353,7 +4398,7 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { * query ports, and some of them may override an existing * wildcard IPv6 port. */ - result = add_listenelt(mctx, list, &addr, ISC_TRUE); + result = add_listenelt(mctx, list, &addr, dscp, ISC_TRUE); if (result != ISC_R_SUCCESS) goto fail; } @@ -4383,12 +4428,14 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { continue; addrp = dns_zone_getnotifysrc6(zone); - result = add_listenelt(mctx, list, addrp, ISC_FALSE); + dscp = dns_zone_getnotifysrc6dscp(zone); + result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE); if (result != ISC_R_SUCCESS) goto fail; addrp = dns_zone_getxfrsource6(zone); - result = add_listenelt(mctx, list, addrp, ISC_FALSE); + dscp = dns_zone_getxfrsource6dscp(zone); + result = add_listenelt(mctx, list, addrp, dscp, ISC_FALSE); if (result != ISC_R_SUCCESS) goto fail; } @@ -5241,6 +5288,11 @@ load_configuration(const char *filename, ns_server_t *server, else CHECKM(ns_config_getport(config, &listen_port), "port"); + /* + * Determing the default DSCP code point. + */ + CHECKM(ns_config_getdscp(config, &ns_g_dscp), "dscp"); + /* * Find the listen queue depth. */ @@ -5277,7 +5329,7 @@ load_configuration(const char *filename, ns_server_t *server, * Not specified, use default. */ CHECK(ns_listenlist_default(ns_g_mctx, listen_port, - ISC_TRUE, &listenon)); + -1, ISC_TRUE, &listenon)); } if (listenon != NULL) { ns_interfacemgr_setlistenon4(server->interfacemgr, @@ -5304,7 +5356,7 @@ load_configuration(const char *filename, ns_server_t *server, * Not specified, use default. */ CHECK(ns_listenlist_default(ns_g_mctx, listen_port, - ISC_TRUE, &listenon)); + -1, ISC_TRUE, &listenon)); } if (listenon != NULL) { ns_interfacemgr_setlistenon6(server->interfacemgr, @@ -6869,8 +6921,9 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, isc_mem_t *mctx, ns_listenelt_t **target) { isc_result_t result; - const cfg_obj_t *portobj; + const cfg_obj_t *portobj, *dscpobj; in_port_t port; + isc_dscp_t dscp = -1; ns_listenelt_t *delt = NULL; REQUIRE(target != NULL && *target == NULL); @@ -6893,7 +6946,20 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, port = (in_port_t)cfg_obj_asuint32(portobj); } - result = ns_listenelt_create(mctx, port, NULL, &delt); + dscpobj = cfg_tuple_get(listener, "dscp"); + if (!cfg_obj_isuint32(dscpobj)) + dscp = ns_g_dscp; + else { + if (cfg_obj_asuint32(dscpobj) > 63) { + cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, + "dscp value '%u' is out of range", + cfg_obj_asuint32(dscpobj)); + return (ISC_R_RANGE); + } + dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); + } + + result = ns_listenelt_create(mctx, port, dscp, NULL, &delt); if (result != ISC_R_SUCCESS) return (result); diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 251f138355..cffe4c5c71 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -807,6 +807,7 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, const char *dupcheck; dns_notifytype_t notifytype = dns_notifytype_yes; isc_sockaddr_t *addrs; + isc_dscp_t *dscps; dns_name_t **keynames; isc_uint32_t count; unsigned int dbargc; @@ -831,6 +832,7 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_zonestat_level_t statlevel; int seconds; dns_zone_t *mayberaw = (raw != NULL) ? raw : zone; + isc_dscp_t dscp; i = 0; if (zconfig != NULL) { @@ -1103,17 +1105,20 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, isc_uint32_t addrcount; addrs = NULL; keynames = NULL; + dscps = NULL; RETERR(ns_config_getipandkeylist(config, obj, mctx, - &addrs, &keynames, + &addrs, &dscps, + &keynames, &addrcount)); - result = dns_zone_setalsonotifywithkeys(zone, addrs, - keynames, + result = dns_zone_setalsonotifydscpkeys(zone, addrs, + dscps, keynames, addrcount); if (addrcount != 0) - ns_config_putipandkeylist(mctx, &addrs, + ns_config_putipandkeylist(mctx, &addrs, &dscps, &keynames, addrcount); else - INSIST(addrs == NULL && keynames == NULL); + INSIST(addrs == NULL && dscps == NULL && + keynames == NULL); RETERR(result); } else RETERR(dns_zone_setalsonotify(zone, NULL, 0)); @@ -1122,12 +1127,20 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, result = ns_config_get(maps, "notify-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setnotifysrc4dscp(zone, dscp)); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setnotifysrc6dscp(zone, dscp)); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; @@ -1550,14 +1563,15 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, (void)cfg_map_get(zoptions, "masters", &obj); if (obj != NULL) { addrs = NULL; + dscps = NULL; keynames = NULL; RETERR(ns_config_getipandkeylist(config, obj, mctx, - &addrs, &keynames, - &count)); + &addrs, &dscps, + &keynames, &count)); result = dns_zone_setmasterswithkeys(mayberaw, addrs, keynames, count); if (count != 0) - ns_config_putipandkeylist(mctx, &addrs, + ns_config_putipandkeylist(mctx, &addrs, &dscps, &keynames, count); else INSIST(addrs == NULL && keynames == NULL); @@ -1609,6 +1623,10 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource4(mayberaw, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setxfrsource4dscp(mayberaw, dscp)); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; @@ -1616,6 +1634,10 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource6(mayberaw, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setxfrsource6dscp(mayberaw, dscp)); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; @@ -1623,12 +1645,20 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource4(mayberaw, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setaltxfrsource4dscp(mayberaw, dscp)); obj = NULL; result = ns_config_get(maps, "alt-transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource6(mayberaw, cfg_obj_assockaddr(obj))); + dscp = cfg_obj_getdscp(obj); + if (dscp == -1) + dscp = ns_g_dscp; + RETERR(dns_zone_setaltxfrsource6dscp(mayberaw, dscp)); obj = NULL; (void)ns_config_get(maps, "use-alt-transfer-source", &obj); diff --git a/bin/tests/adb_test.c b/bin/tests/adb_test.c index 2caf43bf64..967f241d4e 100644 --- a/bin/tests/adb_test.c +++ b/bin/tests/adb_test.c @@ -204,15 +204,17 @@ create_view(void) { attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, - taskmgr, &any4, 512, 6, 1024, - 17, 19, attrs, attrs, &disp4) + taskmgr, &any4, + 512, 6, 1024, 17, 19, + attrs, attrs, &disp4) == ISC_R_SUCCESS); INSIST(disp4 != NULL); attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP; RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, - taskmgr, &any6, 512, 6, 1024, - 17, 19, attrs, attrs, &disp6) + taskmgr, &any6, + 512, 6, 1024, 17, 19, + attrs, attrs, &disp6) == ISC_R_SUCCESS); INSIST(disp6 != NULL); diff --git a/bin/tests/resolver/t_resolver.c b/bin/tests/resolver/t_resolver.c index 27a18ac714..11341e2cc2 100644 --- a/bin/tests/resolver/t_resolver.c +++ b/bin/tests/resolver/t_resolver.c @@ -53,9 +53,9 @@ setup_create_dispatch_v4(void) isc_sockaddr_t local_address; isc_sockaddr_any(&local_address); - CHECK(dns_dispatch_getudp(dispatch_manager, socket_manager, task_manager, - &local_address, 4096, 100, 100, 100, 500, - 0, 0, /* unsigned int attributes, unsigned int mask, */ + CHECK(dns_dispatch_getudp(dispatch_manager, socket_manager, + task_manager, &local_address, + 4096, 100, 100, 100, 500, 0, 0, &dispatch_v4)); } static void diff --git a/bin/tests/system/checkconf/good.conf b/bin/tests/system/checkconf/good.conf index 5444fdde0a..8f0312b49f 100644 --- a/bin/tests/system/checkconf/good.conf +++ b/bin/tests/system/checkconf/good.conf @@ -35,6 +35,7 @@ options { datasize 104857600; deallocate-on-exit yes; directory "."; + dscp 41; dump-file "named_dumpdb"; fake-iquery yes; files 1000; @@ -47,10 +48,10 @@ options { listen-on port 90 { "any"; }; - listen-on port 100 { + listen-on port 100 dscp 33 { 127.0.0.1/32; }; - listen-on-v6 port 53 { + listen-on-v6 port 53 dscp 57 { "none"; }; match-mapped-addresses yes; @@ -67,6 +68,7 @@ options { serial-query-rate 100; server-id none; max-cache-size 20000000000000; + transfer-source 0.0.0.0 dscp 63; zone-statistics none; }; view "first" { @@ -77,6 +79,7 @@ view "first" { type master; file "xxx"; update-policy local; + notify-source 10.10.10.10 port 53 dscp 55; }; dnssec-lookaside auto; dnssec-validation auto; diff --git a/bin/tests/system/checkconf/range.conf b/bin/tests/system/checkconf/range.conf new file mode 100644 index 0000000000..9908df711d --- /dev/null +++ b/bin/tests/system/checkconf/range.conf @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 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. + */ + +options { + port 999999; + dscp 222; + listen-on port 100 dscp 444 { + 127.0.0.1/32; + }; +}; + +zone "example" { + type master; + file "example.db"; +}; diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh index 7cbce53ec4..1d8712a380 100644 --- a/bin/tests/system/checkconf/tests.sh +++ b/bin/tests/system/checkconf/tests.sh @@ -43,6 +43,12 @@ do status=`expr $status + $ret` done +echo "I: checking that named-checkconf catches range errors" +ret=0 +$CHECKCONF range.conf > /dev/null 2>&1 && ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I: checking named-checkconf dnssec warnings" ret=0 $CHECKCONF dnssec.1 2>&1 | grep 'validation yes.*enable no' > /dev/null || ret=1 diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 9f9f25b179..17e60a9104 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -60,7 +60,7 @@ ARPANAME=$TOP/bin/tools/arpaname SUBDIRS="acl additional allow_query addzone autosign builtin cacheclean checkconf @CHECKDS@ checknames checkzone @COVERAGE@ database dlv dlvauto dlz dlzexternal dlzredir dname dns64 dnssec - dsdigest ecdsa formerr forward glue gost ixfr inline limits + dsdigest dscp ecdsa formerr forward glue gost ixfr inline limits logfileconfig lwresd masterfile masterformat metadata notify nsupdate pending pkcs11 redirect resolver rndc rpz rrl rrsetorder rsabigexponent sortlist smartsign staticstub diff --git a/bin/tests/system/dnssec/ns4/named1.conf b/bin/tests/system/dnssec/ns4/named1.conf index 3f7fd05247..d69652a1d7 100644 --- a/bin/tests/system/dnssec/ns4/named1.conf +++ b/bin/tests/system/dnssec/ns4/named1.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; + query-source address 10.53.0.4 dscp 1; + notify-source 10.53.0.4 dscp 2; + transfer-source 10.53.0.4 dscp 3; port 5300; pid-file "named.pid"; listen-on { 10.53.0.4; }; diff --git a/bin/tests/system/dnssec/ns4/named2.conf b/bin/tests/system/dnssec/ns4/named2.conf index 4abf44b436..0158e03a8f 100644 --- a/bin/tests/system/dnssec/ns4/named2.conf +++ b/bin/tests/system/dnssec/ns4/named2.conf @@ -21,9 +21,10 @@ controls { /* empty */ }; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; + query-source address 10.53.0.4 dscp 4; + notify-source 10.53.0.4 dscp 5; + transfer-source 10.53.0.4 dscp 6; + dscp 16; port 5300; pid-file "named.pid"; listen-on { 10.53.0.4; }; diff --git a/bin/tests/system/dscp/clean.sh b/bin/tests/system/dscp/clean.sh new file mode 100644 index 0000000000..d55200e383 --- /dev/null +++ b/bin/tests/system/dscp/clean.sh @@ -0,0 +1,2 @@ +rm -f */root.bk +rm -f dig.out.10.53.0.? diff --git a/bin/tests/system/dscp/ns1/named.args b/bin/tests/system/dscp/ns1/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns1/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns1/named.conf b/bin/tests/system/dscp/ns1/named.conf new file mode 100644 index 0000000000..a7f2344c3d --- /dev/null +++ b/bin/tests/system/dscp/ns1/named.conf @@ -0,0 +1,35 @@ +/* + * 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 { + dscp 46; + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type master; + file "root.db"; +}; diff --git a/bin/tests/system/dscp/ns1/root.db b/bin/tests/system/dscp/ns1/root.db new file mode 100644 index 0000000000..d13075a63e --- /dev/null +++ b/bin/tests/system/dscp/ns1/root.db @@ -0,0 +1,8 @@ +$TTL 3600 +. SOA ns1.nil-servers. marka.isc.org. 1 3600 1200 3600000 1200 +. NS ns1.nil-servers. +. NS ns2.nil-servers. +ns1.nil-servers. A 10.53.0.1 +ns2.nil-servers. A 10.53.0.2 +xxx.example. A 10.53.0.1 +xxx.tld. A 10.53.0.1 diff --git a/bin/tests/system/dscp/ns2/named.args b/bin/tests/system/dscp/ns2/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns2/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns2/named.conf b/bin/tests/system/dscp/ns2/named.conf new file mode 100644 index 0000000000..dbcc97bd7f --- /dev/null +++ b/bin/tests/system/dscp/ns2/named.conf @@ -0,0 +1,36 @@ +/* + * 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 { + dscp 46; + 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; +}; + +zone "." { + type slave; + file "root.bk"; + masters { 10.53.0.1; }; +}; diff --git a/bin/tests/system/dscp/ns3/hint.db b/bin/tests/system/dscp/ns3/hint.db new file mode 100644 index 0000000000..c3df01d362 --- /dev/null +++ b/bin/tests/system/dscp/ns3/hint.db @@ -0,0 +1,5 @@ +$TTL 3600 +. NS ns1.nil-servers. +. NS ns2.nil-servers. +ns1.nil-servers. A 10.53.0.1 +ns2.nil-servers. A 10.53.0.2 diff --git a/bin/tests/system/dscp/ns3/named.args b/bin/tests/system/dscp/ns3/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns3/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns3/named.conf b/bin/tests/system/dscp/ns3/named.conf new file mode 100644 index 0000000000..a12b5e2148 --- /dev/null +++ b/bin/tests/system/dscp/ns3/named.conf @@ -0,0 +1,34 @@ +/* + * 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 { + dscp 46; + query-source address 10.53.0.3; + notify-source 10.53.0.3; + transfer-source 10.53.0.3; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.3; }; + listen-on-v6 { none; }; + notify yes; +}; + +zone "." { + type hint; + file "hint.db"; +}; diff --git a/bin/tests/system/dscp/ns4/named.args b/bin/tests/system/dscp/ns4/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns4/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns4/named.conf b/bin/tests/system/dscp/ns4/named.conf new file mode 100644 index 0000000000..01c5a35325 --- /dev/null +++ b/bin/tests/system/dscp/ns4/named.conf @@ -0,0 +1,35 @@ +/* + * 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 { + dscp 47; + query-source dscp 46 address 10.53.0.4; + notify-source 10.53.0.4 dscp 46; + transfer-source 10.53.0.4 dscp 46; + port 5300; + pid-file "named.pid"; + listen-on dscp 46 { 10.53.0.4; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type master; + file "root.db"; +}; diff --git a/bin/tests/system/dscp/ns4/root.db b/bin/tests/system/dscp/ns4/root.db new file mode 100644 index 0000000000..cfd1adf634 --- /dev/null +++ b/bin/tests/system/dscp/ns4/root.db @@ -0,0 +1,8 @@ +$TTL 3600 +. SOA ns4.nil-servers. marka.isc.org. 1 3600 1200 3600000 1200 +. NS ns4.nil-servers. +. NS ns5.nil-servers. +ns4.nil-servers. A 10.53.0.4 +ns5.nil-servers. A 10.53.0.5 +xxx.example. A 10.53.0.1 +xxx.tld. A 10.53.0.1 diff --git a/bin/tests/system/dscp/ns5/named.args b/bin/tests/system/dscp/ns5/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns5/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns5/named.conf b/bin/tests/system/dscp/ns5/named.conf new file mode 100644 index 0000000000..c33096386b --- /dev/null +++ b/bin/tests/system/dscp/ns5/named.conf @@ -0,0 +1,37 @@ +/* + * 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 { + dscp 47; + query-source dscp 46 address 10.53.0.5; + notify-source 10.53.0.5 dscp 46; + transfer-source 10.53.0.5 dscp 46; + alt-transfer-source 10.53.0.5 dscp 46; + port 5300; + pid-file "named.pid"; + listen-on dscp 46 { 10.53.0.5; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type slave; + file "root.bk"; + masters { 10.53.0.4; }; +}; diff --git a/bin/tests/system/dscp/ns6/hint.db b/bin/tests/system/dscp/ns6/hint.db new file mode 100644 index 0000000000..6527767032 --- /dev/null +++ b/bin/tests/system/dscp/ns6/hint.db @@ -0,0 +1,5 @@ +$TTL 3600 +. NS ns4.nil-servers. +. NS ns5.nil-servers. +ns4.nil-servers. A 10.53.0.4 +ns5.nil-servers. A 10.53.0.5 diff --git a/bin/tests/system/dscp/ns6/named.args b/bin/tests/system/dscp/ns6/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns6/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns6/named.conf b/bin/tests/system/dscp/ns6/named.conf new file mode 100644 index 0000000000..91e9754326 --- /dev/null +++ b/bin/tests/system/dscp/ns6/named.conf @@ -0,0 +1,34 @@ +/* + * 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 { + dscp 47; + query-source dscp 46 address 10.53.0.6; + notify-source 10.53.0.6 dscp 46; + transfer-source 10.53.0.6 dscp 46; + port 5300; + pid-file "named.pid"; + listen-on dscp 46 { 10.53.0.6; }; + listen-on-v6 { none; }; + notify yes; +}; + +zone "." { + type hint; + file "hint.db"; +}; diff --git a/bin/tests/system/dscp/ns7/named.args b/bin/tests/system/dscp/ns7/named.args new file mode 100644 index 0000000000..9b94ece052 --- /dev/null +++ b/bin/tests/system/dscp/ns7/named.args @@ -0,0 +1 @@ +-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns7/named.conf b/bin/tests/system/dscp/ns7/named.conf new file mode 100644 index 0000000000..31e5ac1cec --- /dev/null +++ b/bin/tests/system/dscp/ns7/named.conf @@ -0,0 +1,40 @@ +/* + * 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 { + dscp 47; + query-source dscp 46 address 10.53.0.7; + notify-source 10.53.0.7 dscp 47; + transfer-source 10.53.0.7 dscp 47; + alt-transfer-source 10.53.0.7 dscp 47; + port 5300; + pid-file "named.pid"; + listen-on dscp 46 { 10.53.0.7; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type slave; + file "root.bk"; + transfer-source 10.53.0.7 dscp 46; + notify-source 10.53.0.7 dscp 46; + alt-transfer-source 10.53.0.7 dscp 46; + masters { 10.53.0.4; }; +}; diff --git a/bin/tests/system/dscp/tests.sh b/bin/tests/system/dscp/tests.sh new file mode 100644 index 0000000000..7c767bd8d8 --- /dev/null +++ b/bin/tests/system/dscp/tests.sh @@ -0,0 +1,27 @@ +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +DIGOPTS="+tcp +noadd +nosea +nostat +noquest" + +status=0 + +# +# 10.53.0.1 10.53.0.2 10.53.0.3 have a global dscp setting; +# 10.53.0.4 10.53.0.5 10.53.0.6 have dscp set in option *-source clauses; +# 10.53.0.7 has dscp set in zone *-source clauses; +# +for server in 10.53.0.1 10.53.0.2 10.53.0.3 10.53.0.4 10.53.0.5 \ + 10.53.0.6 10.53.0.7 +do + echo "I:testing root SOA lookup at $server" + for i in 0 1 2 3 4 5 6 7 8 9 + do + ret=0 + $DIG -p 5300 @$server $DIGOPTS soa . > dig.out.$server + grep "status: NOERROR" dig.out.$server > /dev/null || ret=1 + test $ret = 0 && break + sleep 1 + done + test $ret = 0 || { echo "I:failed"; status=`expr $status + $ret`; } +done +exit $status diff --git a/bin/tests/system/nsupdate/ns1/named.conf b/bin/tests/system/nsupdate/ns1/named.conf index 86fe91d070..0fd6148799 100644 --- a/bin/tests/system/nsupdate/ns1/named.conf +++ b/bin/tests/system/nsupdate/ns1/named.conf @@ -20,9 +20,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + query-source address 10.53.0.1 dscp 1; + notify-source 10.53.0.1 dscp 22; + transfer-source 10.53.0.1 dscp 3; port 5300; pid-file "named.pid"; session-keyfile "session.key"; diff --git a/bin/tests/system/nsupdate/ns2/named.conf b/bin/tests/system/nsupdate/ns2/named.conf index 6db32202ff..fc6dd611b8 100644 --- a/bin/tests/system/nsupdate/ns2/named.conf +++ b/bin/tests/system/nsupdate/ns2/named.conf @@ -20,9 +20,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.2; - notify-source 10.53.0.2; - transfer-source 10.53.0.2; + query-source address 10.53.0.2 dscp 4; + notify-source 10.53.0.2 dscp 5; + transfer-source 10.53.0.2 dscp 6; port 5300; pid-file "named.pid"; listen-on { 10.53.0.2; }; diff --git a/bin/tests/system/nsupdate/ns3/named.conf b/bin/tests/system/nsupdate/ns3/named.conf index 4b43efe4f2..8b706e9bd7 100644 --- a/bin/tests/system/nsupdate/ns3/named.conf +++ b/bin/tests/system/nsupdate/ns3/named.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.3; - notify-source 10.53.0.3; - transfer-source 10.53.0.3; + query-source address 10.53.0.3 dscp 7; + notify-source 10.53.0.3 dscp 8; + transfer-source 10.53.0.3 dscp 9; port 5300; pid-file "named.pid"; listen-on { 10.53.0.3; }; diff --git a/bin/tests/system/resolver/ns1/named.conf b/bin/tests/system/resolver/ns1/named.conf index 65068655ea..f249df907a 100644 --- a/bin/tests/system/resolver/ns1/named.conf +++ b/bin/tests/system/resolver/ns1/named.conf @@ -20,9 +20,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.1; - notify-source 10.53.0.1; - transfer-source 10.53.0.1; + query-source address 10.53.0.1 dscp 1; + notify-source 10.53.0.1 dscp 2; + transfer-source 10.53.0.1 dscp 3; port 5300; pid-file "named.pid"; listen-on { 10.53.0.1; }; diff --git a/bin/tests/system/resolver/ns4/named.conf b/bin/tests/system/resolver/ns4/named.conf index 307b07c765..c2275d8e67 100644 --- a/bin/tests/system/resolver/ns4/named.conf +++ b/bin/tests/system/resolver/ns4/named.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.4; - notify-source 10.53.0.4; - transfer-source 10.53.0.4; + query-source address 10.53.0.4 dscp 4; + notify-source 10.53.0.4 dscp 5; + transfer-source 10.53.0.4 dscp 6; port 5300; pid-file "named.pid"; listen-on { 10.53.0.4; }; diff --git a/bin/tests/system/resolver/ns5/named.conf b/bin/tests/system/resolver/ns5/named.conf index 1abedf67f1..4457ae5cfa 100644 --- a/bin/tests/system/resolver/ns5/named.conf +++ b/bin/tests/system/resolver/ns5/named.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.5; - notify-source 10.53.0.5; - transfer-source 10.53.0.5; + query-source address 10.53.0.5 dscp 7; + notify-source 10.53.0.5 dscp 8; + transfer-source 10.53.0.5 dscp 9; port 5300; pid-file "named.pid"; listen-on { 10.53.0.5; }; diff --git a/bin/tests/system/resolver/ns6/named.conf b/bin/tests/system/resolver/ns6/named.conf index 35cccb79df..d8bbf09e11 100644 --- a/bin/tests/system/resolver/ns6/named.conf +++ b/bin/tests/system/resolver/ns6/named.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.6; - notify-source 10.53.0.6; - transfer-source 10.53.0.6; + query-source address 10.53.0.6 dscp 10; + notify-source 10.53.0.6 dscp 11; + transfer-source 10.53.0.6 dscp 12; port 5300; pid-file "named.pid"; listen-on { 10.53.0.6; }; diff --git a/bin/tests/system/resolver/ns7/named.conf b/bin/tests/system/resolver/ns7/named.conf index a41afd0ebc..cde389c283 100644 --- a/bin/tests/system/resolver/ns7/named.conf +++ b/bin/tests/system/resolver/ns7/named.conf @@ -21,9 +21,9 @@ controls { /* empty */ }; options { - query-source address 10.53.0.7; - notify-source 10.53.0.7; - transfer-source 10.53.0.7; + query-source address 10.53.0.7 dscp 13; + notify-source 10.53.0.7 dscp 14; + transfer-source 10.53.0.7 dscp 15; port 5300; pid-file "named.pid"; listen-on { 10.53.0.7; }; diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index df4c02db3b..7bdcc64aaa 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -3279,6 +3279,21 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. + + + + ip_dscp + + + + + A number between 0 and 63, used + to select a differentiated services code point (DSCP) + value for use with outgoing traffic on operating systems + that support DSCP. + + + @@ -5170,8 +5185,8 @@ badresp:1,adberr:0,findfail:0,valfail:0] lwres { - listen-on { ip_addr port ip_port ; - ip_addr port ip_port ; ... }; + listen-on { ip_addr port ip_port dscp ip_dscp ; + ip_addr port ip_port dscp ip_dscp ; ... }; view view_name; search { domain_name ; domain_name ; ... }; ndots number; @@ -5238,7 +5253,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] <command>masters</command> Statement Grammar -masters name port ip_port { ( masters_list | +masters name port ip_port dscp ip_dscp { ( masters_list | ip_addr port ip_port key key ) ; ... }; @@ -5313,10 +5328,10 @@ badresp:1,adberr:0,findfail:0,valfail:0] dnssec-must-be-secure domain yes_or_no; dnssec-accept-expired yes_or_no; forward ( only | first ); - forwarders { ip_addr port ip_port ; ... }; - dual-stack-servers port ip_port { - ( domain_name port ip_port | - ip_addr port ip_port ) ; + forwarders { ip_addr port ip_port dscp ip_dscp ; ... }; + dual-stack-servers port ip_port dscp ip_dscp { + ( domain_name port ip_port dscp ip_dscp | + ip_addr port ip_port dscp ip_dscp) ; ... }; check-names ( master | slave | response ) ( warn | fail | ignore ); @@ -5350,16 +5365,21 @@ badresp:1,adberr:0,findfail:0,valfail:0] avoid-v4-udp-ports { port_list }; use-v6-udp-ports { port_list }; avoid-v6-udp-ports { port_list }; - listen-on port ip_port { address_match_list }; - listen-on-v6 port ip_port { address_match_list }; + listen-on port ip_port dscp ip_dscp { address_match_list }; + listen-on-v6 port ip_port dscp ip_dscp +{ address_match_list }; query-source ( ( ip4_addr | * ) - port ( ip_port | * ) | + port ( ip_port | * ) + dscp ip_dscp | address ( ip4_addr | * ) - port ( ip_port | * ) ) ; + port ( ip_port | * ) ) + dscp ip_dscp ; query-source-v6 ( ( ip6_addr | * ) - port ( ip_port | * ) | + port ( ip_port | * ) + dscp ip_dscp | address ( ip6_addr | * ) - port ( ip_port | * ) ) ; + port ( ip_port | * ) ) + dscp ip_dscp ; use-queryport-pool yes_or_no; queryport-pool-ports number; queryport-pool-updateinterval number; @@ -5377,19 +5397,18 @@ badresp:1,adberr:0,findfail:0,valfail:0] transfers-in number; transfers-out number; transfers-per-ns number; - transfer-source (ip4_addr | *) port ip_port ; - transfer-source-v6 (ip6_addr | *) port ip_port ; - alt-transfer-source (ip4_addr | *) port ip_port ; - alt-transfer-source-v6 (ip6_addr | *) - port ip_port ; + transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; + transfer-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; + alt-transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; + alt-transfer-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; use-alt-transfer-source yes_or_no; notify-delay seconds ; - notify-source (ip4_addr | *) port ip_port ; - notify-source-v6 (ip6_addr | *) port ip_port ; + notify-source (ip4_addr | *) port ip_port dscp ip_dscp ; + notify-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; notify-to-soa yes_or_no ; also-notify { ip_addr - port ip_port key keyname ; - ip_addr port ip_port key keyname ; ... }; + port ip_port dscp ip_dscp key keyname ; + ip_addr port ip_port dscp ip_dscp key keyname ; ... }; max-ixfr-log-size number; max-journal-size size_spec; coresize size_spec ; @@ -5420,6 +5439,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] min-retry-time number ; max-retry-time number ; port ip_port; + dscp ip_dscp ; additional-from-auth yes_or_no ; additional-from-cache yes_or_no ; random-device path_name ; @@ -10275,14 +10295,14 @@ ns.domain.com.rpz-nsdname CNAME . transfers number ; transfer-format ( one-answer | many-answers ) ; ] keys { string ; string ; ... } ; - transfer-source (ip4_addr | *) port ip_port ; - transfer-source-v6 (ip6_addr | *) port ip_port ; - notify-source (ip4_addr | *) port ip_port ; - notify-source-v6 (ip6_addr | *) port ip_port ; + transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; + transfer-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; + notify-source (ip4_addr | *) port ip_port dscp ip_dscp ; + notify-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; query-source address ( ip_addr | * ) - port ( ip_port | * ) ; + port ( ip_port | * ) dscp ip_dscp ; query-source-v6 address ( ip_addr | * ) - port ( ip_port | * ) ; + port ( ip_port | * ) dscp ip_dscp ; use-queryport-pool yes_or_no; queryport-pool-ports number; queryport-pool-updateinterval number; @@ -10930,8 +10950,8 @@ view "external" { dnssec-dnskey-kskonly yes_or_no; dnssec-loadkeys-interval number; update-policy local | { update_policy_rule ... }; - also-notify { ip_addr port ip_port ; - ip_addr port ip_port ; ... }; + also-notify { ip_addr port ip_port dscp ip_dscp ; + ip_addr port ip_port dscp ip_dscp ; ... }; check-names (warn|fail|ignore) ; check-mx (warn|fail|ignore) ; check-wildcard yes_or_no; @@ -10942,7 +10962,7 @@ view "external" { journal string ; max-journal-size size_spec; forward (only|first) ; - forwarders { ip_addr port ip_port ; ... }; + forwarders { ip_addr port ip_port dscp ip_dscp ; ... }; ixfr-base string ; ixfr-from-differences yes_or_no; ixfr-tmp-file string ; @@ -10955,8 +10975,8 @@ view "external" { notify-delay seconds ; notify-to-soa yes_or_no; pubkey number number number string ; - notify-source (ip4_addr | *) port ip_port ; - notify-source-v6 (ip6_addr | *) port ip_port ; + notify-source (ip4_addr | *) port ip_port dscp ip_dscp ; + notify-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; zone-statistics full | terse | none; sig-validity-interval number number ; sig-signing-nodes number ; @@ -10987,8 +11007,9 @@ zone zone_name class dnssec-loadkeys-interval number; dnssec-secure-to-insecure yes_or_no ; try-tcp-refresh yes_or_no; - also-notify port ip_port { ( masters_list | ip_addr + also-notify port ip_port dscp ip_dscp { ( masters_list | ip_addr port ip_port + dscp ip_dscp key key ) ; ... }; check-names (warn|fail|ignore) ; dialup dialup_option ; @@ -10997,13 +11018,14 @@ zone zone_name class journal string ; max-journal-size size_spec; forward (only|first) ; - forwarders { ip_addr port ip_port ; ... }; + forwarders { ip_addr port ip_port dscp ip_dscp ; ... }; ixfr-base string ; ixfr-from-differences yes_or_no; ixfr-tmp-file string ; maintain-ixfr-base yes_or_no ; - masters port ip_port { ( masters_list | ip_addr + masters port ip_port dscp ip_dscp { ( masters_list | ip_addr port ip_port + dscp ip_dscp key key ) ; ... }; max-ixfr-log-size number ; max-transfer-idle-in number ; @@ -11014,14 +11036,15 @@ zone zone_name class notify-delay seconds ; notify-to-soa yes_or_no; pubkey number number number string ; - transfer-source (ip4_addr | *) port ip_port ; - transfer-source-v6 (ip6_addr | *) port ip_port ; - alt-transfer-source (ip4_addr | *) port ip_port ; + transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; + transfer-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; + alt-transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; alt-transfer-source-v6 (ip6_addr | *) - port ip_port ; + port ip_port + dscp ip_dscp ; use-alt-transfer-source yes_or_no; - notify-source (ip4_addr | *) port ip_port ; - notify-source-v6 (ip6_addr | *) port ip_port ; + notify-source (ip4_addr | *) port ip_port dscp ip_dscp ; + notify-source-v6 (ip6_addr | *) port ip_port dscp ip_dscp ; zone-statistics full | terse | none; sig-validity-interval number number ; sig-signing-nodes number ; @@ -11056,19 +11079,20 @@ zone zone_name class file string ; masterfile-format (text|raw|map) ; forward (only|first) ; - forwarders { ip_addr port ip_port ; ... }; - masters port ip_port { ( masters_list | ip_addr + forwarders { ip_addr port ip_port dscp ip_dscp ; ... }; + masters port ip_port dscp ip_dscp { ( masters_list | ip_addr port ip_port + dscp ip_dscp key key ) ; ... }; max-transfer-idle-in number ; max-transfer-time-in number ; pubkey number number number string ; - transfer-source (ip4_addr | *) port ip_port ; + transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; transfer-source-v6 (ip6_addr | *) - port ip_port ; - alt-transfer-source (ip4_addr | *) port ip_port ; + port ip_port dscp ip_dscp ; + alt-transfer-source (ip4_addr | *) port ip_port dscp ip_dscp ; alt-transfer-source-v6 (ip6_addr | *) - port ip_port ; + port ip_port dscp ip_dscp ; use-alt-transfer-source yes_or_no; zone-statistics yes_or_no ; database string ; @@ -11090,7 +11114,7 @@ zone zone_name classzone_name class { type forward; forward (only|first) ; - forwarders { ip_addr port ip_port ; ... }; + forwarders { ip_addr port ip_port dscp ip_dscp ; ... }; delegation-only yes_or_no ; }; diff --git a/doc/design/dscp b/doc/design/dscp new file mode 100644 index 0000000000..cc9fdedaab --- /dev/null +++ b/doc/design/dscp @@ -0,0 +1,133 @@ + + Differentiate Services Code Point Support + +$Id: dscp,v 1.1.2.1 2012/02/24 05:20:36 marka Exp $ + +Differentiate Services Code Point (DSCP) is implemented in IPv4 using the +TOS octet and in IPv6 using the TCLASS octet. + +RFC 3542 defines the api to manipulate the TCLASS octet as part of +the advanced socket API. TCLASS is settable on both a socket and +packet basis (setsockopt/sendmsg) and the sent value can be retrieved +using recvmsg over UDP. Retrieval is undefined for TCP. + +The Advanced socket API was not incorporated into the POSIX socket +API for IPv6 and may not be completely implemented in any OS. + +For TOS setsockopt() supports setting of the field on a persocket +basis. TOS may also be set on a per packet basis on some OS using +sendmsg. If it is not supported the sendmsg call reports a error. +Support can only be determined by attempted to send a packet with +the option set. Retrieval of the sent TOS value is retrievable on +Linux. This can be determined at compile time. + +DSCP values need to be compatible with TOS values as it is a re-use +of the field. + +LIBISC: + +We will need to be able to probe for the level of DSCP support. We +need to know if we can set it at the socket level, packet level and +if we can retrieve the DSCP value sent. This needs to be done +independently for IPv4 and IPv6. + +#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */ +#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */ +#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */ +#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */ +#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */ +#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */ +#define ISC_NET_DSCPALL 0x3f /* All valid flags */ + +unsigned int +isc_net_probedscp(void); +/*%< + * Probe the level of DSCP support. + */ + +We also need to be able to set DSCP values on a per socket basis, per packet +basis and to retrieve dscp values from received packet. + +Setting dscp on a per socket basis shall be done using isc_socket_dscp. + +void +isc_socket_dscp(isc_socket_t *sock, unsigned int dscp); +/*%< + * Requires: + *\li 'sock' is a valid socket. + */ +/*@}*/ + +isc_socketevent shall be extended to support the sending of and retrieval +of DSCP values. If ISC_SOCKEVENTATTR_DSCP is set then isc_socket_sendto2 +shall set the DSCP value. isc_socket_recv shall set ISC_SOCKEVENTATTR_DSCP +and the dscp element if the OS returns the value via recvmsg. + +#define ISC_SOCKEVENTATTR_DSCP 0x00040000U /* public */ + +struct isc_socketevent { + ISC_EVENT_COMMON(isc_socketevent_t); + isc_result_t result; /*%< OK, EOF, whatever else */ + unsigned int minimum; /*%< minimum i/o for event */ + unsigned int n; /*%< bytes read or written */ + unsigned int offset; /*%< offset into buffer list */ + isc_region_t region; /*%< for single-buffer i/o */ + isc_bufferlist_t bufferlist; /*%< list of buffers */ + isc_sockaddr_t address; /*%< source address */ + isc_time_t timestamp; /*%< timestamp of packet recv */ + struct in6_pktinfo pktinfo; /*%< ipv6 pktinfo */ + isc_uint32_t attributes; /*%< see below */ + isc_eventdestructor_t destroy; /*%< original destructor */ + unsigned int dscp; /*%< UDP dscp value */ +}; + +A convience function will be provided to allocate and intialize the structure. + +isc_socketevent_t * +isc_socket_socketevent(isc_socket_t *sock0, isc_eventtype_t eventtype, + isc_taskaction_t action, const void *arg) + +NAMED/LIBDNS: + +Named needs to be able to set the DSCP value of sent traffic. We should +be able to set DSCP for all TCP connections. + +For UDP we should have a default DSCP value for when we can't set this on +a per packet basis with the ability to override for specific destinations. + +options/view/server; +tcp-dscp ; +udp-dscp ; + +http://bogpeople.com/networking/dscp.shtml list a set of TOS compatible +values (below). + +DSCP Name DS Field Value IP Precedence + Binary Decimal +CS0 000 000 0 0 +CS1 001 000 8 1 +AF11 001 010 10 1 +AF12 001 100 12 1 +AF13 001 110 14 1 +CS2 010 000 16 2 +AF21 010 010 18 2 +AF22 010 100 20 2 +AF23 010 110 22 2 +CS3 011 000 24 3 +AF31 011 010 26 3 +AF32 011 100 28 3 +AF33 011 110 30 3 +CS4 100 000 32 4 +AF41 100 010 34 4 +AF42 100 100 36 4 +AF43 100 110 38 4 +CS5 101 000 40 5 +EF 101 110 46 5 +CS6 110 000 48 6 +CS7 111 000 56 7 + +CS Class Selector (RFC 2474) +AFxy Assured Forwarding (x=class, y=drop precedence) (RFC2597) +EF Expedited Forwarding (RFC 3246) + +value should be one of these or a numeric 0..63. The default value is 0. diff --git a/doc/misc/options b/doc/misc/options index 723645ca4b..6069010ec4 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -38,8 +38,8 @@ logging { }; lwres { - listen-on [ port ] { ( | ) - [ port ]; ... }; + listen-on [ port ] [ dscp ] { ( + | ) [ port ] [ dscp ]; ... }; ndots ; search { ; ... }; view ; @@ -48,8 +48,9 @@ lwres { managed-keys { ; ... }; -masters [ port ] { ( | [ port - ] | [ port ] ) [ key ]; ... }; +masters [ port ] [ dscp ] { ( | + [ port ] | [ port ] ) + [ key ]; ... }; options { acache-cleaning-interval ; @@ -68,12 +69,13 @@ options { allow-update { ; ... }; allow-update-forwarding { ; ... }; allow-v6-synthesis { ; ... }; // obsolete - also-notify [ port ] { ( | [ - port ] | [ port ] ) [ key - ]; ... }; - alt-transfer-source ( | * ) [ port ( | * ) ]; + also-notify [ port ] [ dscp ] { ( | + [ port ] | [ port + ] ) [ key ]; ... }; + alt-transfer-source ( | * ) [ port ( | * ) + ] [ dscp ]; alt-transfer-source-v6 ( | * ) [ port ( | - * ) ]; + * ) ] [ dscp ]; attach-cache ; auth-nxdomain ; // default changed auto-dnssec ( allow | maintain | off ); @@ -123,9 +125,11 @@ options { dnssec-secure-to-insecure ; dnssec-update-mode ( maintain | no-resign ); dnssec-validation ( yes | no | auto ); + dscp ; dual-stack-servers [ port ] { ( [ port - ] | [ port ] | - [ port ] ); ... }; + ] [ dscp ] | [ port + ] [ dscp ] | [ port + ] [ dscp ] ); ... }; dump-file ; edns-udp-size ; empty-contact ; @@ -134,13 +138,13 @@ options { fake-iquery ; // obsolete fetch-glue ; // obsolete files ; - filter-aaaa { ; ... }; // not configured - filter-aaaa-on-v4 ; // not configured - filter-aaaa-on-v6 ; // not configured + filter-aaaa { ; ... }; + filter-aaaa-on-v4 ; + filter-aaaa-on-v6 ; flush-zones-on-shutdown ; forward ( first | only ); - forwarders [ port ] { ( | ) - [ port ]; ... }; + forwarders [ port ] [ dscp ] { ( + | ) [ port ] [ dscp ]; ... }; has-old-clients ; // obsolete heartbeat-interval ; host-statistics ; // not implemented @@ -151,8 +155,10 @@ options { ixfr-from-differences ; key-directory ; lame-ttl ; - listen-on [ port ] { ; ... }; - listen-on-v6 [ port ] { ; ... }; + listen-on [ port ] [ dscp ] { + ; ... }; + listen-on-v6 [ port ] [ dscp ] { + ; ... }; maintain-ixfr-base ; // obsolete managed-keys-directory ; masterfile-format ( text | raw | map ); @@ -183,8 +189,10 @@ options { named-xfer ; // obsolete notify ; notify-delay ; - notify-source ( | * ) [ port ( | * ) ]; - notify-source-v6 ( | * ) [ port ( | * ) ]; + notify-source ( | * ) [ port ( | * ) ] [ + dscp ]; + notify-source-v6 ( | * ) [ port ( | * ) ] + [ dscp ]; notify-to-soa ; nsec3-test-zone ; // test only pid-file ( | none ); @@ -256,8 +264,10 @@ options { tkey-gssapi-keytab ; topology { ; ... }; // not implemented transfer-format ( many-answers | one-answer ); - transfer-source ( | * ) [ port ( | * ) ]; - transfer-source-v6 ( | * ) [ port ( | * ) ]; + transfer-source ( | * ) [ port ( | * ) ] [ + dscp ]; + transfer-source-v6 ( | * ) [ port ( | * ) + ] [ dscp ]; transfers-in ; transfers-out ; transfers-per-ns ; @@ -282,16 +292,20 @@ server { edns-udp-size ; keys ; max-udp-size ; - notify-source ( | * ) [ port ( | * ) ]; - notify-source-v6 ( | * ) [ port ( | * ) ]; + notify-source ( | * ) [ port ( | * ) ] [ + dscp ]; + notify-source-v6 ( | * ) [ port ( | * ) ] + [ dscp ]; provide-ixfr ; query-source ; query-source-v6 ; request-ixfr ; support-ixfr ; // obsolete transfer-format ( many-answers | one-answer ); - transfer-source ( | * ) [ port ( | * ) ]; - transfer-source-v6 ( | * ) [ port ( | * ) ]; + transfer-source ( | * ) [ port ( | * ) ] [ + dscp ]; + transfer-source-v6 ( | * ) [ port ( | * ) + ] [ dscp ]; transfers ; }; @@ -319,12 +333,13 @@ view { allow-update { ; ... }; allow-update-forwarding { ; ... }; allow-v6-synthesis { ; ... }; // obsolete - also-notify [ port ] { ( | [ - port ] | [ port ] ) [ key - ]; ... }; - alt-transfer-source ( | * ) [ port ( | * ) ]; + also-notify [ port ] [ dscp ] { ( | + [ port ] | [ port + ] ) [ key ]; ... }; + alt-transfer-source ( | * ) [ port ( | * ) + ] [ dscp ]; alt-transfer-source-v6 ( | * ) [ port ( | - * ) ]; + * ) ] [ dscp ]; attach-cache ; auth-nxdomain ; // default changed auto-dnssec ( allow | maintain | off ); @@ -372,19 +387,20 @@ view { dnssec-update-mode ( maintain | no-resign ); dnssec-validation ( yes | no | auto ); dual-stack-servers [ port ] { ( [ port - ] | [ port ] | - [ port ] ); ... }; + ] [ dscp ] | [ port + ] [ dscp ] | [ port + ] [ dscp ] ); ... }; edns-udp-size ; empty-contact ; empty-server ; empty-zones-enable ; fetch-glue ; // obsolete - filter-aaaa { ; ... }; // not configured - filter-aaaa-on-v4 ; // not configured - filter-aaaa-on-v6 ; // not configured + filter-aaaa { ; ... }; + filter-aaaa-on-v4 ; + filter-aaaa-on-v6 ; forward ( first | only ); - forwarders [ port ] { ( | ) - [ port ]; ... }; + forwarders [ port ] [ dscp ] { ( + | ) [ port ] [ dscp ]; ... }; inline-signing ; ixfr-from-differences ; key { @@ -421,8 +437,10 @@ view { multi-master ; notify ; notify-delay ; - notify-source ( | * ) [ port ( | * ) ]; - notify-source-v6 ( | * ) [ port ( | * ) ]; + notify-source ( | * ) [ port ( | * ) ] [ + dscp ]; + notify-source-v6 ( | * ) [ port ( | * ) ] + [ dscp ]; notify-to-soa ; nsec3-test-zone ; // test only preferred-glue ; @@ -471,9 +489,9 @@ view { keys ; max-udp-size ; notify-source ( | * ) [ port ( | * - ) ]; + ) ] [ dscp ]; notify-source-v6 ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; provide-ixfr ; query-source ; query-source-v6 ; @@ -481,9 +499,9 @@ view { support-ixfr ; // obsolete transfer-format ( many-answers | one-answer ); transfer-source ( | * ) [ port ( | - * ) ]; + * ) ] [ dscp ]; transfer-source-v6 ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; transfers ; }; sig-signing-nodes ; @@ -494,8 +512,10 @@ view { suppress-initial-notify ; // not yet implemented topology { ; ... }; // not implemented transfer-format ( many-answers | one-answer ); - transfer-source ( | * ) [ port ( | * ) ]; - transfer-source-v6 ( | * ) [ port ( | * ) ]; + transfer-source ( | * ) [ port ( | * ) ] [ + dscp ]; + transfer-source-v6 ( | * ) [ port ( | * ) + ] [ dscp ]; trusted-keys { ; ... }; try-tcp-refresh ; @@ -511,13 +531,14 @@ view { allow-transfer { ; ... }; allow-update { ; ... }; allow-update-forwarding { ; ... }; - also-notify [ port ] { ( | - [ port ] | [ - port ] ) [ key ]; ... }; + also-notify [ port ] [ dscp ] { ( + | [ port ] | + [ port ] ) [ key ]; + ... }; alt-transfer-source ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; alt-transfer-source-v6 ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; auto-dnssec ( allow | maintain | off ); check-dup-records ( fail | warn | ignore ); check-integrity ; @@ -537,8 +558,9 @@ view { dnssec-update-mode ( maintain | no-resign ); file ; forward ( first | only ); - forwarders [ port ] { ( | - ) [ port ]; ... }; + forwarders [ port ] [ dscp ] { ( + | ) [ port ] [ + dscp ]; ... }; inline-signing ; ixfr-base ; // obsolete ixfr-from-differences ; @@ -547,9 +569,9 @@ view { key-directory ; maintain-ixfr-base ; // obsolete masterfile-format ( text | raw | map ); - masters [ port ] { ( | [ - port ] | [ port ] ) - [ key ]; ... }; + masters [ port ] [ dscp ] { ( + | [ port ] | [ + port ] ) [ key ]; ... }; max-ixfr-log-size ; // obsolete max-journal-size ; max-refresh-time ; @@ -564,9 +586,9 @@ view { notify ; notify-delay ; notify-source ( | * ) [ port ( | * - ) ]; + ) ] [ dscp ]; notify-source-v6 ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; notify-to-soa ; nsec3-test-zone ; // test only pubkey @@ -581,9 +603,9 @@ view { sig-signing-type ; sig-validity-interval [ ]; transfer-source ( | * ) [ port ( | - * ) ]; + * ) ] [ dscp ]; transfer-source-v6 ( | * ) [ port ( - | * ) ]; + | * ) ] [ dscp ]; try-tcp-refresh ; type ( master | slave | stub | static-stub | hint | forward | delegation-only | redirect ); @@ -607,12 +629,13 @@ zone { allow-transfer { ; ... }; allow-update { ; ... }; allow-update-forwarding { ; ... }; - also-notify [ port ] { ( | [ - port ] | [ port ] ) [ key - ]; ... }; - alt-transfer-source ( | * ) [ port ( | * ) ]; + also-notify [ port ] [ dscp ] { ( | + [ port ] | [ port + ] ) [ key ]; ... }; + alt-transfer-source ( | * ) [ port ( | * ) + ] [ dscp ]; alt-transfer-source-v6 ( | * ) [ port ( | - * ) ]; + * ) ] [ dscp ]; auto-dnssec ( allow | maintain | off ); check-dup-records ( fail | warn | ignore ); check-integrity ; @@ -632,8 +655,8 @@ zone { dnssec-update-mode ( maintain | no-resign ); file ; forward ( first | only ); - forwarders [ port ] { ( | ) - [ port ]; ... }; + forwarders [ port ] [ dscp ] { ( + | ) [ port ] [ dscp ]; ... }; inline-signing ; ixfr-base ; // obsolete ixfr-from-differences ; @@ -642,9 +665,9 @@ zone { key-directory ; maintain-ixfr-base ; // obsolete masterfile-format ( text | raw | map ); - masters [ port ] { ( | [ port - ] | [ port ] ) [ key - ]; ... }; + masters [ port ] [ dscp ] { ( | + [ port ] | [ port + ] ) [ key ]; ... }; max-ixfr-log-size ; // obsolete max-journal-size ; max-refresh-time ; @@ -658,8 +681,10 @@ zone { multi-master ; notify ; notify-delay ; - notify-source ( | * ) [ port ( | * ) ]; - notify-source-v6 ( | * ) [ port ( | * ) ]; + notify-source ( | * ) [ port ( | * ) ] [ + dscp ]; + notify-source-v6 ( | * ) [ port ( | * ) ] + [ dscp ]; notify-to-soa ; nsec3-test-zone ; // test only pubkey ; // obsolete @@ -672,8 +697,10 @@ zone { sig-signing-signatures ; sig-signing-type ; sig-validity-interval [ ]; - transfer-source ( | * ) [ port ( | * ) ]; - transfer-source-v6 ( | * ) [ port ( | * ) ]; + transfer-source ( | * ) [ port ( | * ) ] [ + dscp ]; + transfer-source-v6 ( | * ) [ port ( | * ) + ] [ dscp ]; try-tcp-refresh ; type ( master | slave | stub | static-stub | hint | forward | delegation-only | redirect ); diff --git a/lib/bind9/check.c b/lib/bind9/check.c index a7041ff2f8..b5658a192c 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -747,6 +747,28 @@ typedef enum { optlevel_zone } optlevel_t; +static isc_result_t +check_dscp(const cfg_obj_t *options, isc_log_t *logctx) { + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *obj = NULL; + + /* + * Check that DSCP setting is within range + */ + obj = NULL; + (void)cfg_map_get(options, "dscp", &obj); + if (obj != NULL) { + isc_uint32_t dscp = cfg_obj_asuint32(obj); + if (dscp >= 64) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "'dscp' out of range (0-63)"); + result = ISC_R_FAILURE; + } + } + + return (result); +} + static isc_result_t check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, optlevel_t optlevel) @@ -1128,6 +1150,10 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, result = ISC_R_FAILURE; } + tresult = check_dscp(options, logctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + return (result); } diff --git a/lib/dns/adb.c b/lib/dns/adb.c index f3ab6d3e98..8c10f99be1 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -1946,6 +1946,7 @@ new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) { ai->srtt = entry->srtt; ai->flags = entry->flags; ai->entry = entry; + ai->dscp = -1; ISC_LINK_INIT(ai, publink); return (ai); diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 96684a379f..bf95970485 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -228,6 +228,7 @@ struct dns_dispatch { isc_socket_t *socket; /*%< isc socket attached to */ isc_sockaddr_t local; /*%< local address */ in_port_t localport; /*%< local UDP port */ + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ unsigned int maxrequests; /*%< max requests */ isc_event_t *ctlevent; @@ -2624,6 +2625,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, dispatch_initrandom(&disp->arc4ctx, mgr->entropy, NULL); disp->port_table = NULL; disp->portpool = NULL; + disp->dscp = -1; result = isc_mutex_init(&disp->lock); if (result != ISC_R_SUCCESS) @@ -3863,6 +3865,18 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { *dsetp = NULL; } +void +dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) { + REQUIRE(VALID_DISPATCH(disp)); + disp->dscp = dscp; +} + +isc_dscp_t +dns_dispatch_getdscp(dns_dispatch_t *disp) { + REQUIRE(VALID_DISPATCH(disp)); + return (disp->dscp); +} + #if 0 void dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { diff --git a/lib/dns/forward.c b/lib/dns/forward.c index 7ec4e5c9de..9a3105b642 100644 --- a/lib/dns/forward.c +++ b/lib/dns/forward.c @@ -83,13 +83,63 @@ dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) { return (result); } +isc_result_t +dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, dns_name_t *name, + dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy) +{ + isc_result_t result; + dns_forwarders_t *forwarders; + dns_forwarder_t *fwd, *nfwd; + + REQUIRE(VALID_FWDTABLE(fwdtable)); + + forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t)); + if (forwarders == NULL) + return (ISC_R_NOMEMORY); + + ISC_LIST_INIT(forwarders->fwdrs); + for (fwd = ISC_LIST_HEAD(*fwdrs); + fwd != NULL; + fwd = ISC_LIST_NEXT(fwd, link)) + { + nfwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t)); + if (nfwd == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + *nfwd = *fwd; + ISC_LINK_INIT(nfwd, link); + ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link); + } + forwarders->fwdpolicy = fwdpolicy; + + RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); + result = dns_rbt_addname(fwdtable->table, name, forwarders); + RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); + + if (result != ISC_R_SUCCESS) + goto cleanup; + + return (ISC_R_SUCCESS); + + cleanup: + while (!ISC_LIST_EMPTY(forwarders->fwdrs)) { + fwd = ISC_LIST_HEAD(forwarders->fwdrs); + ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link); + isc_mem_put(fwdtable->mctx, fwd, sizeof(isc_sockaddr_t)); + } + isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); + return (result); +} + isc_result_t dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) { isc_result_t result; dns_forwarders_t *forwarders; - isc_sockaddr_t *sa, *nsa; + dns_forwarder_t *fwd; + isc_sockaddr_t *sa; REQUIRE(VALID_FWDTABLE(fwdtable)); @@ -97,19 +147,20 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, if (forwarders == NULL) return (ISC_R_NOMEMORY); - ISC_LIST_INIT(forwarders->addrs); + ISC_LIST_INIT(forwarders->fwdrs); for (sa = ISC_LIST_HEAD(*addrs); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { - nsa = isc_mem_get(fwdtable->mctx, sizeof(isc_sockaddr_t)); - if (nsa == NULL) { + fwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t)); + if (fwd == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - *nsa = *sa; - ISC_LINK_INIT(nsa, link); - ISC_LIST_APPEND(forwarders->addrs, nsa, link); + fwd->addr = *sa; + fwd->dscp = -1; + ISC_LINK_INIT(fwd, link); + ISC_LIST_APPEND(forwarders->fwdrs, fwd, link); } forwarders->fwdpolicy = fwdpolicy; @@ -123,10 +174,10 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, return (ISC_R_SUCCESS); cleanup: - while (!ISC_LIST_EMPTY(forwarders->addrs)) { - sa = ISC_LIST_HEAD(forwarders->addrs); - ISC_LIST_UNLINK(forwarders->addrs, sa, link); - isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t)); + while (!ISC_LIST_EMPTY(forwarders->fwdrs)) { + fwd = ISC_LIST_HEAD(forwarders->fwdrs); + ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link); + isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t)); } isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); return (result); @@ -202,14 +253,14 @@ static void auto_detach(void *data, void *arg) { dns_forwarders_t *forwarders = data; dns_fwdtable_t *fwdtable = arg; - isc_sockaddr_t *sa; + dns_forwarder_t *fwd; UNUSED(arg); - while (!ISC_LIST_EMPTY(forwarders->addrs)) { - sa = ISC_LIST_HEAD(forwarders->addrs); - ISC_LIST_UNLINK(forwarders->addrs, sa, link); - isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t)); + while (!ISC_LIST_EMPTY(forwarders->fwdrs)) { + fwd = ISC_LIST_HEAD(forwarders->fwdrs); + ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link); + isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t)); } isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); } diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index a5a312406a..92a46d4ba2 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -214,7 +214,9 @@ struct dns_adbaddrinfo { unsigned int magic; /*%< private */ isc_sockaddr_t sockaddr; /*%< [rw] */ - unsigned int srtt; /*%< [rw] microseconds */ + unsigned int srtt; /*%< [rw] microsecs */ + isc_dscp_t dscp; + unsigned int flags; /*%< [rw] */ dns_adbentry_t *entry; /*%< private */ ISC_LINK(dns_adbaddrinfo_t) publink; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 1235f7ca40..d369c9cf64 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -558,6 +558,18 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp); *\li dset is valid */ +void +dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp); +isc_dscp_t +dns_dispatch_getdscp(dns_dispatch_t *disp); +/*%< + * Set/get the DSCP value to be used when sending responses to clients, + * as defined in the "listen-on" or "listen-on-v6" statements. + * + * Requires: + *\li disp is valid. + */ + ISC_LANG_ENDDECLS #endif /* DNS_DISPATCH_H */ diff --git a/lib/dns/include/dns/forward.h b/lib/dns/include/dns/forward.h index 23e94be789..b666d01ce7 100644 --- a/lib/dns/include/dns/forward.h +++ b/lib/dns/include/dns/forward.h @@ -29,8 +29,16 @@ ISC_LANG_BEGINDECLS +struct dns_forwarder { + isc_sockaddr_t addr; + isc_dscp_t dscp; + ISC_LINK(dns_forwarder_t) link; +}; + +typedef ISC_LIST(struct dns_forwarder) dns_forwarderlist_t; + struct dns_forwarders { - isc_sockaddrlist_t addrs; + dns_forwarderlist_t fwdrs; dns_fwdpolicy_t fwdpolicy; }; @@ -49,17 +57,22 @@ dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep); */ isc_result_t +dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, dns_name_t *name, + dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t policy); +isc_result_t dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, isc_sockaddrlist_t *addrs, dns_fwdpolicy_t policy); /*%< * Adds an entry to the forwarding table. The entry associates * a domain with a list of forwarders and a forwarding policy. The - * addrs list is copied if not empty, so the caller should free its copy. + * addrs/fwdrs list is copied if not empty, so the caller should free + * its copy. * * Requires: * \li fwdtable is a valid forwarding table. * \li name is a valid name - * \li addrs is a valid list of sockaddrs, which may be empty. + * \li addrs/fwdrs is a valid list of isc_sockaddr/dns_forwarder + * structures, which may be empty. * * Returns: * \li #ISC_R_SUCCESS diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h index 86324a3d70..6665174bb4 100644 --- a/lib/dns/include/dns/peer.h +++ b/lib/dns/include/dns/peer.h @@ -76,8 +76,11 @@ struct dns_peer { isc_boolean_t request_nsid; dns_name_t *key; isc_sockaddr_t *transfer_source; + isc_dscp_t transfer_dscp; isc_sockaddr_t *notify_source; + isc_dscp_t notify_dscp; isc_sockaddr_t *query_source; + isc_dscp_t query_dscp; isc_uint16_t udpsize; /* receive size */ isc_uint16_t maxudp; /* transmit size */ @@ -214,6 +217,23 @@ dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source); isc_result_t dns_peer_getquerysource(dns_peer_t *peer, isc_sockaddr_t *query_source); +isc_result_t +dns_peer_setnotifydscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_getnotifydscp(dns_peer_t *peer, isc_dscp_t *dscpp); + +isc_result_t +dns_peer_settransferdscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_gettransferdscp(dns_peer_t *peer, isc_dscp_t *dscpp); + +isc_result_t +dns_peer_setquerydscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_getquerydscp(dns_peer_t *peer, isc_dscp_t *dscpp); ISC_LANG_ENDDECLS #endif /* DNS_PEER_H */ diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 8c792ddd57..43cec7e56b 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -195,7 +195,7 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, *\li requestp != NULL && *requestp == NULL */ -/*% See dns_request_createvia3() */ +/*% See dns_request_createvia4() */ isc_result_t dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -204,7 +204,7 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_taskaction_t action, void *arg, dns_request_t **requestp); -/*% See dns_request_createvia3() */ +/*% See dns_request_createvia4() */ isc_result_t dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -213,6 +213,7 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); +/*% See dns_request_createvia4() */ isc_result_t dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -221,6 +222,15 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); + +isc_result_t +dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + isc_dscp_t dscp, unsigned int options, + dns_tsigkey_t *key, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_request_t **requestp); /*%< * Create and send a request. * @@ -254,7 +264,7 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, *\li requestp != NULL && *requestp == NULL */ -/*% See dns_request_createraw3() */ +/*% See dns_request_createraw4() */ isc_result_t dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -262,7 +272,7 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); -/*% See dns_request_createraw3() */ +/*% See dns_request_createraw4() */ isc_result_t dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -271,6 +281,7 @@ dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_taskaction_t action, void *arg, dns_request_t **requestp); +/*% See dns_request_createraw4() */ isc_result_t dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, @@ -278,6 +289,15 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, unsigned int udptimeout, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); + +isc_result_t +dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + isc_dscp_t dscp, unsigned int options, + unsigned int timeout, unsigned int udptimeout, + unsigned int udpretries, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp); /*!< * \brief Create and send a request. * diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index b96724fb75..9c03be7ad6 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -598,6 +598,23 @@ dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp); * \li resolver to be valid. */ +void +dns_resolver_setquerydscp4(dns_resolver_t *resolver, isc_dscp_t dscp); +isc_dscp_t +dns_resolver_getquerydscp4(dns_resolver_t *resolver); + +void +dns_resolver_setquerydscp6(dns_resolver_t *resolver, isc_dscp_t dscp); +isc_dscp_t +dns_resolver_getquerydscp6(dns_resolver_t *resolver); +/*% + * Get and set the DSCP values for the resolver's IPv4 and IPV6 query + * sources. + * + * Requires: + * \li resolver to be valid. + */ + ISC_LANG_ENDDECLS #endif /* DNS_RESOLVER_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index c5bda694ae..894dc17b0d 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -80,6 +80,7 @@ typedef struct dns_dumpctx dns_dumpctx_t; typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; typedef struct dns_forwarders dns_forwarders_t; +typedef struct dns_forwarder dns_forwarder_t; typedef struct dns_fwdtable dns_fwdtable_t; typedef struct dns_iptable dns_iptable_t; typedef isc_uint32_t dns_iterations_t; diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index 2f20c35f4d..8ec42c4332 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -67,6 +67,14 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp); + +isc_result_t +dns_xfrin_create3(dns_zone_t *zone, dns_rdatatype_t xfrtype, + isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr, + isc_dscp_t dscp, dns_tsigkey_t *tsigkey, isc_mem_t *mctx, + isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, + isc_task_t *task, dns_xfrindone_t done, + dns_xfrin_ctx_t **xfrp); /*%< * Attempt to start an incoming zone transfer of 'zone' * from 'masteraddr', creating a dns_xfrin_ctx_t object to diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index e6806e8df5..4c6198203b 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -597,7 +597,11 @@ dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, isc_uint32_t count); isc_result_t dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, - dns_name_t **keynames, isc_uint32_t count); + dns_name_t **keynames, isc_uint32_t count); +isc_result_t +dns_zone_setalsonotifydscpkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, + const isc_dscp_t *dscps, dns_name_t **keynames, + isc_uint32_t count); /*%< * Set the list of additional servers to be notified when * a zone changes. To clear the list use 'count = 0'. @@ -730,6 +734,32 @@ dns_zone_getaltxfrsource4(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_result_t +dns_zone_setxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp); +isc_result_t +dns_zone_setaltxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_dscp_t +dns_zone_getxfrsource4dscp(dns_zone_t *zone); +isc_dscp_t +dns_zone_getaltxfrsource4dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + + isc_result_t dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource); isc_result_t @@ -758,6 +788,31 @@ dns_zone_getaltxfrsource6(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_dscp_t +dns_zone_getxfrsource6dscp(dns_zone_t *zone); +isc_dscp_t +dns_zone_getaltxfrsource6dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp); +isc_result_t +dns_zone_setaltxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + isc_result_t dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc); /*%< @@ -781,6 +836,36 @@ dns_zone_getnotifysrc4(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_dscp_t +dns_zone_getnotifysrc4dscp(dns_zone_t *zone); +/*%/ + * Get the DCSP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setnotifysrc4dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_dscp_t +dns_zone_getnotifysrc4dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + isc_result_t dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc); /*%< @@ -804,6 +889,36 @@ dns_zone_getnotifysrc6(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_dscp_t +dns_zone_getnotifysrc6dscp(dns_zone_t *zone); +/*%/ + * Get the DCSP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setnotifysrc6dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_dscp_t +dns_zone_getnotifysrc6dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + void dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl); /*%< diff --git a/lib/dns/peer.c b/lib/dns/peer.c index ec9e08cb27..9c75b13b9d 100644 --- a/lib/dns/peer.c +++ b/lib/dns/peer.c @@ -710,3 +710,57 @@ dns_peer_getmaxudp(dns_peer_t *peer, isc_uint16_t *maxudp) { return (ISC_R_NOTFOUND); } } + +isc_result_t +dns_peer_setnotifydscp(dns_peer_t *peer, isc_dscp_t dscp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscp < 64); + + peer->notify_dscp = dscp; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_getnotifydscp(dns_peer_t *peer, isc_dscp_t *dscpp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscpp != NULL); + + *dscpp = peer->notify_dscp; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_settransferdscp(dns_peer_t *peer, isc_dscp_t dscp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscp < 64); + + peer->transfer_dscp = dscp; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_gettransferdscp(dns_peer_t *peer, isc_dscp_t *dscpp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscpp != NULL); + + *dscpp = peer->transfer_dscp; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_setquerydscp(dns_peer_t *peer, isc_dscp_t dscp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscp < 64); + + peer->query_dscp = dscp; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_getquerydscp(dns_peer_t *peer, isc_dscp_t *dscpp) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(dscpp != NULL); + + *dscpp = peer->query_dscp; + return (ISC_R_SUCCESS); +} diff --git a/lib/dns/request.c b/lib/dns/request.c index 1316e69941..9b32a41506 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -89,6 +89,7 @@ struct dns_request { isc_boolean_t canceling; /* ctlevent outstanding */ isc_sockaddr_t destaddr; unsigned int udpcount; + isc_dscp_t dscp; }; #define DNS_REQUEST_F_CONNECTING 0x0001 @@ -427,6 +428,7 @@ static inline isc_result_t req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) { isc_region_t r; isc_socket_t *socket; + isc_socketevent_t *sendevent; isc_result_t result; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); @@ -439,8 +441,19 @@ req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) { * as we do in resolver.c, but we prefer implementation simplicity * at this moment. */ - result = isc_socket_sendto(socket, &r, task, req_senddone, - request, address, NULL); + sendevent = isc_socket_socketevent(request->mctx, socket, + ISC_SOCKEVENT_SENDDONE, + req_senddone, request); + if (request->dscp == -1) { + sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = 0; + } else { + sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = request->dscp; + } + + result = isc_socket_sendto2(socket, &r, task, address, NULL, + sendevent, 0); if (result == ISC_R_SUCCESS) request->flags |= DNS_REQUEST_F_SENDING; return (result); @@ -471,6 +484,7 @@ new_request(isc_mem_t *mctx, dns_request_t **requestp) request->requestmgr = NULL; request->tsig = NULL; request->tsigkey = NULL; + request->dscp = -1; ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL, DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, NULL); @@ -510,7 +524,8 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, isc_sockaddr_t *destaddr) { static isc_result_t create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, - isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) + isc_sockaddr_t *destaddr, isc_dscp_t dscp, + dns_dispatch_t **dispatchp) { isc_result_t result; isc_socket_t *socket = NULL; @@ -536,6 +551,7 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, if (result != ISC_R_SUCCESS) goto cleanup; #endif + attrs = 0; attrs |= DNS_DISPATCHATTR_TCP; attrs |= DNS_DISPATCHATTR_PRIVATE; @@ -544,6 +560,8 @@ create_tcp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, else attrs |= DNS_DISPATCHATTR_IPV6; attrs |= DNS_DISPATCHATTR_MAKEQUERY; + + isc_socket_dscp(socket, dscp); result = dns_dispatch_createtcp(requestmgr->dispatchmgr, socket, requestmgr->taskmgr, 4096, 2, 1, 1, 3, attrs, @@ -609,12 +627,12 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, static isc_result_t get_dispatch(isc_boolean_t tcp, dns_requestmgr_t *requestmgr, isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, - dns_dispatch_t **dispatchp) + isc_dscp_t dscp, dns_dispatch_t **dispatchp) { isc_result_t result; if (tcp) result = create_tcp_dispatch(requestmgr, srcaddr, - destaddr, dispatchp); + destaddr, dscp, dispatchp); else result = find_udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp); @@ -646,8 +664,8 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return(dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr, - options, timeout, 0, 0, task, action, + return(dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr, + 0, options, timeout, 0, 0, task, action, arg, requestp)); } @@ -664,8 +682,8 @@ dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if (udptimeout != 0) udpretries = timeout / udptimeout; - return (dns_request_createraw3(requestmgr, msgbuf, srcaddr, destaddr, - options, timeout, udptimeout, + return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr, + 0, options, timeout, udptimeout, udpretries, task, action, arg, requestp)); } @@ -677,6 +695,21 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, unsigned int udptimeout, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) +{ + return (dns_request_createraw4(requestmgr, msgbuf, srcaddr, destaddr, + 0, options, timeout, udptimeout, + udpretries, task, action, arg, + requestp)); +} + +isc_result_t +dns_request_createraw4(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + isc_dscp_t dscp, unsigned int options, + unsigned int timeout, unsigned int udptimeout, + unsigned int udpretries, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; @@ -715,6 +748,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, udptimeout = 1; } request->udpcount = udpretries; + request->dscp = dscp; /* * Create timer now. We will set it below once. @@ -746,7 +780,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) tcp = ISC_TRUE; - result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, + result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp, &request->dispatch); if (result != ISC_R_SUCCESS) goto cleanup; @@ -833,8 +867,8 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return (dns_request_createvia3(requestmgr, message, NULL, address, - options, key, timeout, 0, 0, task, + return (dns_request_createvia4(requestmgr, message, NULL, address, + 0, options, key, timeout, 0, 0, task, action, arg, requestp)); } @@ -846,8 +880,8 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_taskaction_t action, void *arg, dns_request_t **requestp) { - return(dns_request_createvia3(requestmgr, message, srcaddr, destaddr, - options, key, timeout, 0, 0, task, + return(dns_request_createvia4(requestmgr, message, srcaddr, destaddr, + 0, options, key, timeout, 0, 0, task, action, arg, requestp)); } @@ -863,8 +897,8 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message, if (udptimeout != 0) udpretries = timeout / udptimeout; - return (dns_request_createvia3(requestmgr, message, srcaddr, destaddr, - options, key, timeout, udptimeout, + return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr, + 0, options, key, timeout, udptimeout, udpretries, task, action, arg, requestp)); } @@ -877,6 +911,21 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp) +{ + return (dns_request_createvia4(requestmgr, message, srcaddr, destaddr, + 0, options, key, timeout, udptimeout, + udpretries, task, action, arg, + requestp)); +} + +isc_result_t +dns_request_createvia4(dns_requestmgr_t *requestmgr, dns_message_t *message, + isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + isc_dscp_t dscp, unsigned int options, + dns_tsigkey_t *key, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; @@ -917,6 +966,7 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, udptimeout = 1; } request->udpcount = udpretries; + request->dscp = dscp; /* * Create timer now. We will set it below once. @@ -943,7 +993,7 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, use_tcp: tcp = ISC_TF((options & DNS_REQUESTOPT_TCP) != 0); - result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, + result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, dscp, &request->dispatch); if (result != ISC_R_SUCCESS) goto cleanup; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 232709a049..5c220b7b32 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -161,6 +161,7 @@ typedef struct query { isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; isc_socketevent_t sendevent; + isc_dscp_t dscp; unsigned int options; unsigned int attributes; unsigned int sends; @@ -226,7 +227,7 @@ struct fetchctx { dns_adbfind_t * altfind; dns_adbaddrinfolist_t forwaddrs; dns_adbaddrinfolist_t altaddrs; - isc_sockaddrlist_t forwarders; + dns_forwarderlist_t forwarders; dns_fwdpolicy_t fwdpolicy; isc_sockaddrlist_t bad; isc_sockaddrlist_t edns; @@ -397,6 +398,8 @@ struct dns_resolver { dns_dispatchset_t * dispatches4; isc_boolean_t exclusivev4; dns_dispatchset_t * dispatches6; + isc_dscp_t querydscp4; + isc_dscp_t querydscp6; isc_boolean_t exclusivev6; unsigned int nbuckets; fctxbucket_t * buckets; @@ -1402,6 +1405,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_sockaddr_t addr; isc_boolean_t have_addr = ISC_FALSE; unsigned int srtt; + isc_dscp_t dscp = -1; FCTXTRACE("query"); @@ -1436,6 +1440,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->attributes = 0; query->sends = 0; query->connects = 0; + query->dscp = addrinfo->dscp; /* * Note that the caller MUST guarantee that 'addrinfo' will remain * valid until this query is canceled. @@ -1462,9 +1467,13 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = dns_peer_getquerysource(peer, &addr); if (result == ISC_R_SUCCESS) have_addr = ISC_TRUE; + result = dns_peer_getquerydscp(peer, &dscp); + if (result == ISC_R_SUCCESS) + query->dscp = dscp; } } + dscp = -1; if ((query->options & DNS_FETCHOPT_TCP) != 0) { int pf; @@ -1475,11 +1484,13 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = dns_dispatch_getlocaladdress( res->dispatches4->dispatches[0], &addr); + dscp = dns_resolver_getquerydscp4(fctx->res); break; case PF_INET6: result = dns_dispatch_getlocaladdress( res->dispatches6->dispatches[0], &addr); + dscp = dns_resolver_getquerydscp6(fctx->res); break; default: result = ISC_R_NOTIMPLEMENTED; @@ -1489,6 +1500,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, goto cleanup_query; } isc_sockaddr_setport(&addr, 0); + if (query->dscp == -1) + query->dscp = dscp; result = isc_socket_create(res->socketmgr, pf, isc_sockettype_tcp, @@ -1501,7 +1514,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (result != ISC_R_SUCCESS) goto cleanup_socket; #endif - /* * A dispatch will be created once the connect succeeds. */ @@ -1512,9 +1524,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, switch (isc_sockaddr_pf(&addr)) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; + dscp = dns_resolver_getquerydscp4(fctx->res); break; case AF_INET6: attrs |= DNS_DISPATCHATTR_IPV6; + dscp = dns_resolver_getquerydscp6(fctx->res); break; default: result = ISC_R_NOTIMPLEMENTED; @@ -1539,18 +1553,23 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_resolver_dispatchv4(res), &query->dispatch); query->exclusivesocket = res->exclusivev4; + dscp = dns_resolver_getquerydscp4(fctx->res); break; case PF_INET6: dns_dispatch_attach( dns_resolver_dispatchv6(res), &query->dispatch); query->exclusivesocket = res->exclusivev6; + dscp = dns_resolver_getquerydscp6(fctx->res); break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } } + + if (query->dscp == -1) + query->dscp = dscp; /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher @@ -1574,6 +1593,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * * XXXRTH Should we attach to the socket? */ + if (query->dscp != -1) + isc_socket_dscp(query->tcpsocket, query->dscp); result = isc_socket_connect(query->tcpsocket, &addrinfo->sockaddr, task, resquery_connected, query); @@ -2027,9 +2048,21 @@ resquery_send(resquery_t *query) { * XXXRTH Make sure we don't send to ourselves! We should probably * prune out these addresses when we get them from the ADB. */ + memset(&query->sendevent, 0, sizeof(query->sendevent)); ISC_EVENT_INIT(&query->sendevent, sizeof(query->sendevent), 0, NULL, ISC_SOCKEVENT_SENDDONE, resquery_senddone, query, NULL, NULL, NULL); + + if (query->dscp == -1) { + query->sendevent.attributes &= ~ISC_SOCKEVENTATTR_DSCP; + query->sendevent.dscp = 0; + } else { + query->sendevent.attributes |= ISC_SOCKEVENTATTR_DSCP; + query->sendevent.dscp = query->dscp; + if ((query->options & DNS_FETCHOPT_TCP) != 0) + isc_socket_dscp(socket, query->dscp); + } + result = isc_socket_sendto2(socket, &r, task, address, NULL, &query->sendevent, 0); if (result != ISC_R_SUCCESS) { @@ -2609,7 +2642,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { dns_resolver_t *res; isc_stdtime_t now; unsigned int stdoptions = 0; - isc_sockaddr_t *sa; + dns_forwarder_t *fwd; dns_adbaddrinfo_t *ai; isc_boolean_t all_bad; dns_rdata_ns_t ns; @@ -2640,8 +2673,8 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { * selective forwarders specified in the view; otherwise use the * resolver's forwarders (if any). */ - sa = ISC_LIST_HEAD(fctx->forwarders); - if (sa == NULL) { + fwd = ISC_LIST_HEAD(fctx->forwarders); + if (fwd == NULL) { dns_forwarders_t *forwarders = NULL; dns_name_t *name = &fctx->name; dns_name_t suffix; @@ -2666,7 +2699,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { result = dns_fwdtable_find2(fctx->res->view->fwdtable, name, domain, &forwarders); if (result == ISC_R_SUCCESS) { - sa = ISC_LIST_HEAD(forwarders->addrs); + fwd = ISC_LIST_HEAD(forwarders->fwdrs); fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy == dns_fwdpolicy_only && isstrictsubdomain(domain, &fctx->domain)) { @@ -2680,20 +2713,20 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { } } - while (sa != NULL) { - if ((isc_sockaddr_pf(sa) == AF_INET && + while (fwd != NULL) { + if ((isc_sockaddr_pf(&fwd->addr) == AF_INET && fctx->res->dispatches4 == NULL) || - (isc_sockaddr_pf(sa) == AF_INET6 && + (isc_sockaddr_pf(&fwd->addr) == AF_INET6 && fctx->res->dispatches6 == NULL)) { - sa = ISC_LIST_NEXT(sa, link); + fwd = ISC_LIST_NEXT(fwd, link); continue; } ai = NULL; - result = dns_adb_findaddrinfo(fctx->adb, - sa, &ai, 0); /* XXXMLG */ + result = dns_adb_findaddrinfo(fctx->adb, &fwd->addr, &ai, 0); if (result == ISC_R_SUCCESS) { dns_adbaddrinfo_t *cur; ai->flags |= FCTX_ADDRINFO_FORWARDER; + ai->dscp = fwd->dscp; cur = ISC_LIST_HEAD(fctx->forwaddrs); while (cur != NULL && cur->srtt < ai->srtt) cur = ISC_LIST_NEXT(cur, publink); @@ -2703,7 +2736,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { else ISC_LIST_APPEND(fctx->forwaddrs, ai, publink); } - sa = ISC_LIST_NEXT(sa, link); + fwd = ISC_LIST_NEXT(fwd, link); } /* @@ -2852,8 +2885,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { } static inline void -possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr) -{ +possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr) { isc_netaddr_t na; char buf[ISC_NETADDR_FORMATSIZE]; isc_sockaddr_t *sa; @@ -9129,3 +9161,30 @@ dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int seconds) { resolver->query_timeout = seconds; } + +void +dns_resolver_setquerydscp4(dns_resolver_t *resolver, isc_dscp_t dscp) { + REQUIRE(VALID_RESOLVER(resolver)); + + resolver->querydscp4 = dscp; +} + +isc_dscp_t +dns_resolver_getquerydscp4(dns_resolver_t *resolver) { + REQUIRE(VALID_RESOLVER(resolver)); + return (resolver->querydscp4); +} + +void +dns_resolver_setquerydscp6(dns_resolver_t *resolver, isc_dscp_t dscp) { + REQUIRE(VALID_RESOLVER(resolver)); + + resolver->querydscp6 = dscp; +} + +isc_dscp_t +dns_resolver_getquerydscp6(dns_resolver_t *resolver) { + REQUIRE(VALID_RESOLVER(resolver)); + return (resolver->querydscp6); +} + diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index a663f912ee..48fe2b6df8 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -180,12 +180,14 @@ dns_dispatch_cancel dns_dispatch_changeattributes dns_dispatch_createtcp dns_dispatch_detach +dns_dispatch_getdscp dns_dispatch_getlocaladdress dns_dispatch_getsocket dns_dispatch_getudp dns_dispatch_getudp_dup dns_dispatch_importrecv dns_dispatch_removeresponse +dns_dispatch_setdscp dns_dispatch_starttcp dns_dispatchmgr_create dns_dispatchmgr_destroy @@ -456,11 +458,17 @@ dns_peer_detach dns_peer_getbogus dns_peer_getkey dns_peer_getmaxudp +dns_peer_getnotifysource +dns_peer_getnotifydscp dns_peer_getprovideixfr +dns_peer_getquerysource +dns_peer_getquerydscp dns_peer_getrequestixfr dns_peer_getsupportedns dns_peer_gettransferformat dns_peer_gettransfers +dns_peer_gettransfersource +dns_peer_gettransferdscp dns_peer_new dns_peer_newprefix dns_peer_setbogus @@ -468,14 +476,17 @@ dns_peer_setkey dns_peer_setkeybycharp dns_peer_setmaxudp dns_peer_setnotifysource +dns_peer_setnotifydscp dns_peer_setprovideixfr dns_peer_setquerysource +dns_peer_setquerydscp dns_peer_setrequestixfr dns_peer_setrequestnsid dns_peer_setsupportedns dns_peer_settransferformat dns_peer_settransfers dns_peer_settransfersource +dns_peer_settransferdscp dns_peer_setudpsize dns_peerlist_addpeer dns_peerlist_attach @@ -825,6 +836,8 @@ dns_zone_forwardupdate dns_zone_fulldumptostream dns_zone_get_rpz_num dns_zone_getadded +dns_zone_getaltxfrsource4dscp +dns_zone_getaltxfrsource6dscp dns_zone_getchecknames dns_zone_getclass dns_zone_getdb @@ -843,7 +856,9 @@ dns_zone_getmctx dns_zone_getmgr dns_zone_getnotifyacl dns_zone_getnotifysrc4 +dns_zone_getnotifysrc4dscp dns_zone_getnotifysrc6 +dns_zone_getnotifysrc6dscp dns_zone_getoptions dns_zone_getorigin dns_zone_getprivatetype @@ -867,7 +882,9 @@ dns_zone_getupdatedisabled dns_zone_getview dns_zone_getxfracl dns_zone_getxfrsource4 +dns_zone_getxfrsource4dscp dns_zone_getxfrsource6 +dns_zone_getxfrsource6dscp dns_zone_getzeronosoattl dns_zone_iattach dns_zone_idetach @@ -896,7 +913,9 @@ dns_zone_setadded dns_zone_setalsonotify dns_zone_setalsonotifywithkeys dns_zone_setaltxfrsource4 +dns_zone_setaltxfrsource4dscp dns_zone_setaltxfrsource6 +dns_zone_setaltxfrsource6dscp dns_zone_setcheckmx dns_zone_setchecknames dns_zone_setcheckns @@ -928,7 +947,9 @@ dns_zone_setnodes dns_zone_setnotifyacl dns_zone_setnotifydelay dns_zone_setnotifysrc4 +dns_zone_setnotifysrc4dscp dns_zone_setnotifysrc6 +dns_zone_setnotifysrc6dscp dns_zone_setnotifytype dns_zone_setnsec3param dns_zone_setoption @@ -955,7 +976,9 @@ dns_zone_setupdatedisabled dns_zone_setview dns_zone_setxfracl dns_zone_setxfrsource4 +dns_zone_setxfrsource4dscp dns_zone_setxfrsource6 +dns_zone_setxfrsource6dscp dns_zone_setzeronosoattl dns_zone_signwithkey dns_zone_synckeyzone diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 66e3fae329..ad676b74d0 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -121,6 +121,7 @@ struct dns_xfrin_ctx { * may differ due to IXFR->AXFR fallback. */ dns_rdatatype_t reqtype; + isc_dscp_t dscp; isc_sockaddr_t masteraddr; isc_sockaddr_t sourceaddr; @@ -192,6 +193,7 @@ xfrin_create(isc_mem_t *mctx, dns_rdatatype_t reqtype, isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr, + isc_dscp_t dscp, dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp); @@ -606,20 +608,23 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp) { isc_sockaddr_t sourceaddr; + isc_dscp_t dscp; switch (isc_sockaddr_pf(masteraddr)) { case PF_INET: sourceaddr = *dns_zone_getxfrsource4(zone); + dscp = dns_zone_getxfrsource4dscp(zone); break; case PF_INET6: sourceaddr = *dns_zone_getxfrsource6(zone); + dscp = dns_zone_getxfrsource6dscp(zone); break; default: INSIST(0); } - return(dns_xfrin_create2(zone, xfrtype, masteraddr, &sourceaddr, - tsigkey, mctx, timermgr, socketmgr, + return(dns_xfrin_create3(zone, xfrtype, masteraddr, &sourceaddr, + dscp, tsigkey, mctx, timermgr, socketmgr, task, done, xfrp)); } @@ -630,6 +635,19 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp) +{ + return (dns_xfrin_create3(zone, xfrtype, masteraddr, sourceaddr, -1, + tsigkey, mctx, timermgr, socketmgr, task, + done, xfrp)); +} + +isc_result_t +dns_xfrin_create3(dns_zone_t *zone, dns_rdatatype_t xfrtype, + isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr, + isc_dscp_t dscp, dns_tsigkey_t *tsigkey, isc_mem_t *mctx, + isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, + isc_task_t *task, dns_xfrindone_t done, + dns_xfrin_ctx_t **xfrp) { dns_name_t *zonename = dns_zone_getorigin(zone); dns_xfrin_ctx_t *xfr = NULL; @@ -645,7 +663,7 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename, dns_zone_getclass(zone), xfrtype, masteraddr, - sourceaddr, tsigkey, &xfr)); + sourceaddr, dscp, tsigkey, &xfr)); CHECK(xfrin_start(xfr)); @@ -768,6 +786,7 @@ xfrin_create(isc_mem_t *mctx, dns_rdatatype_t reqtype, isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr, + isc_dscp_t dscp, dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp) { @@ -800,6 +819,7 @@ xfrin_create(isc_mem_t *mctx, xfr->checkid = ISC_TRUE; xfr->id = (isc_uint16_t)(tmp & 0xffff); xfr->reqtype = reqtype; + xfr->dscp = dscp; /* sockaddr */ xfr->socket = NULL; @@ -891,6 +911,7 @@ xfrin_start(dns_xfrin_ctx_t *xfr) { CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr, ISC_SOCKET_REUSEADDRESS)); #endif + isc_socket_dscp(xfr->socket, xfr->dscp); CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task, xfrin_connect_done, xfr)); xfr->connects++; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index d69f5118a3..27af000884 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -243,6 +243,7 @@ struct dns_zone { isc_uint32_t minretry; isc_sockaddr_t *masters; + isc_dscp_t *masterdscps; dns_name_t **masterkeynames; isc_boolean_t *mastersok; unsigned int masterscnt; @@ -251,6 +252,7 @@ struct dns_zone { dns_notifytype_t notifytype; isc_sockaddr_t *notify; dns_name_t **notifykeynames; + isc_dscp_t *notifydscp; unsigned int notifycnt; isc_sockaddr_t notifyfrom; isc_task_t *task; @@ -262,6 +264,12 @@ struct dns_zone { isc_sockaddr_t altxfrsource4; isc_sockaddr_t altxfrsource6; isc_sockaddr_t sourceaddr; + isc_dscp_t notifysrc4dscp; + isc_dscp_t notifysrc6dscp; + isc_dscp_t xfrsource4dscp; + isc_dscp_t xfrsource6dscp; + isc_dscp_t altxfrsource4dscp; + isc_dscp_t altxfrsource6dscp; dns_xfrin_ctx_t *xfr; /* task locked */ dns_tsigkey_t *tsigkey; /* key used for xfr */ /* Access Control Lists */ @@ -512,6 +520,7 @@ struct dns_notify { dns_name_t ns; isc_sockaddr_t dst; dns_tsigkey_t *key; + isc_dscp_t dscp; ISC_LINK(dns_notify_t) link; }; @@ -869,12 +878,14 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->maxretry = DNS_ZONE_MAXRETRY; zone->minretry = DNS_ZONE_MINRETRY; zone->masters = NULL; + zone->masterdscps = NULL; zone->masterkeynames = NULL; zone->mastersok = NULL; zone->masterscnt = 0; zone->curmaster = 0; zone->notify = NULL; zone->notifykeynames = NULL; + zone->notifydscp = NULL; zone->notifytype = dns_notifytype_yes; zone->notifycnt = 0; zone->task = NULL; @@ -904,6 +915,12 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_sockaddr_any6(&zone->xfrsource6); isc_sockaddr_any(&zone->altxfrsource4); isc_sockaddr_any6(&zone->altxfrsource6); + zone->notifysrc4dscp = -1; + zone->notifysrc6dscp = -1; + zone->xfrsource4dscp = -1; + zone->xfrsource6dscp = -1; + zone->altxfrsource4dscp = -1; + zone->altxfrsource6dscp = -1; zone->xfr = NULL; zone->tsigkey = NULL; zone->maxxfrin = MAX_XFER_TIME; @@ -4778,6 +4795,23 @@ dns_zone_getxfrsource4(dns_zone_t *zone) { return (&zone->xfrsource4); } +isc_result_t +dns_zone_setxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->xfrsource4dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_dscp_t +dns_zone_getxfrsource4dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->xfrsource4dscp); +} + isc_result_t dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -4795,6 +4829,23 @@ dns_zone_getxfrsource6(dns_zone_t *zone) { return (&zone->xfrsource6); } +isc_dscp_t +dns_zone_getxfrsource6dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->xfrsource6dscp); +} + +isc_result_t +dns_zone_setxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->xfrsource6dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + isc_result_t dns_zone_setaltxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *altxfrsource) @@ -4814,6 +4865,23 @@ dns_zone_getaltxfrsource4(dns_zone_t *zone) { return (&zone->altxfrsource4); } +isc_result_t +dns_zone_setaltxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->altxfrsource4dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_dscp_t +dns_zone_getaltxfrsource4dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->altxfrsource4dscp); +} + isc_result_t dns_zone_setaltxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *altxfrsource) @@ -4833,6 +4901,23 @@ dns_zone_getaltxfrsource6(dns_zone_t *zone) { return (&zone->altxfrsource6); } +isc_result_t +dns_zone_setaltxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->altxfrsource6dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_dscp_t +dns_zone_getaltxfrsource6dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->altxfrsource6dscp); +} + isc_result_t dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -4850,6 +4935,23 @@ dns_zone_getnotifysrc4(dns_zone_t *zone) { return (&zone->notifysrc4); } +isc_result_t +dns_zone_setnotifysrc4dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->notifysrc4dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_dscp_t +dns_zone_getnotifysrc4dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->notifysrc4dscp); +} + isc_result_t dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -4899,25 +5001,33 @@ same_keynames(dns_name_t **old, dns_name_t **new, isc_uint32_t count) { } static void -clear_addresskeylist(isc_sockaddr_t **addrsp, dns_name_t ***keynamesp, - unsigned int *countp, isc_mem_t *mctx) +clear_addresskeylist(isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, + dns_name_t ***keynamesp, unsigned int *countp, + isc_mem_t *mctx) { unsigned int count; isc_sockaddr_t *addrs; + isc_dscp_t *dscps; dns_name_t **keynames; - REQUIRE(countp != NULL && addrsp != NULL && keynamesp != NULL); + REQUIRE(countp != NULL && addrsp != NULL && dscpsp != NULL && + keynamesp != NULL); count = *countp; *countp = 0; addrs = *addrsp; *addrsp = NULL; + dscps = *dscpsp; + *dscpsp = NULL; keynames = *keynamesp; *keynamesp = NULL; if (addrs != NULL) isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t)); + if (dscps != NULL) + isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t)); + if (keynames != NULL) { unsigned int i; for (i = 0; i < count; i++) { @@ -4935,15 +5045,18 @@ clear_addresskeylist(isc_sockaddr_t **addrsp, dns_name_t ***keynamesp, static isc_result_t set_addrkeylist(unsigned int count, const isc_sockaddr_t *addrs, isc_sockaddr_t **newaddrsp, + const isc_dscp_t *dscp, isc_dscp_t **newdscpp, dns_name_t **names, dns_name_t ***newnamesp, isc_mem_t *mctx) { isc_result_t result; isc_sockaddr_t *newaddrs = NULL; + isc_dscp_t *newdscp = NULL; dns_name_t **newnames = NULL; unsigned int i; REQUIRE(newaddrsp != NULL && *newaddrsp == NULL); + REQUIRE(newdscpp != NULL && *newdscpp == NULL); REQUIRE(newnamesp != NULL && *newnamesp == NULL); newaddrs = isc_mem_get(mctx, count * sizeof(*newaddrs)); @@ -4951,10 +5064,22 @@ set_addrkeylist(unsigned int count, return (ISC_R_NOMEMORY); memcpy(newaddrs, addrs, count * sizeof(*newaddrs)); - newnames = NULL; + if (dscp != NULL) { + newdscp = isc_mem_get(mctx, count * sizeof(*newdscp)); + if (newdscp == NULL) { + isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs)); + return (ISC_R_NOMEMORY); + } + memcpy(newdscp, dscp, count * sizeof(*newdscp)); + } else + newdscp = NULL; + if (names != NULL) { newnames = isc_mem_get(mctx, count * sizeof(*newnames)); if (newnames == NULL) { + if (newdscp != NULL) + isc_mem_put(mctx, newdscp, + count * sizeof(*newdscp)); isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs)); return (ISC_R_NOMEMORY); } @@ -4978,32 +5103,64 @@ set_addrkeylist(unsigned int count, mctx); isc_mem_put(mctx, newaddrs, count * sizeof(*newaddrs)); + isc_mem_put(mctx, newdscp, + count * sizeof(*newdscp)); isc_mem_put(mctx, newnames, count * sizeof(*newnames)); return (ISC_R_NOMEMORY); } } } - } + } else + newnames = NULL; + *newdscpp = newdscp; *newaddrsp = newaddrs; *newnamesp = newnames; return (ISC_R_SUCCESS); } +isc_result_t +dns_zone_setnotifysrc6dscp(dns_zone_t *zone, isc_dscp_t dscp) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->notifysrc6dscp = dscp; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_dscp_t +dns_zone_getnotifysrc6dscp(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->notifysrc6dscp); +} + isc_result_t dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, isc_uint32_t count) { - return (dns_zone_setalsonotifywithkeys(zone, notify, NULL, count)); + return (dns_zone_setalsonotifydscpkeys(zone, notify, NULL, NULL, + count)); } isc_result_t dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, dns_name_t **keynames, isc_uint32_t count) +{ + return (dns_zone_setalsonotifydscpkeys(zone, notify, NULL, keynames, + count)); +} + +isc_result_t +dns_zone_setalsonotifydscpkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, + const isc_dscp_t *dscps, dns_name_t **keynames, + isc_uint32_t count) { isc_result_t result; isc_sockaddr_t *newaddrs = NULL; + isc_dscp_t *newdscps = NULL; dns_name_t **newnames = NULL; REQUIRE(DNS_ZONE_VALID(zone)); @@ -5018,8 +5175,9 @@ dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, same_keynames(zone->notifykeynames, keynames, count)) goto unlock; - clear_addresskeylist(&zone->notify, &zone->notifykeynames, - &zone->notifycnt, zone->mctx); + clear_addresskeylist(&zone->notify, &zone->notifydscp, + &zone->notifykeynames, &zone->notifycnt, + zone->mctx); if (count == 0) goto unlock; @@ -5027,7 +5185,7 @@ dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, /* * Set up the notify and notifykey lists */ - result = set_addrkeylist(count, notify, &newaddrs, + result = set_addrkeylist(count, notify, &newaddrs, dscps, &newdscps, keynames, &newnames, zone->mctx); if (result != ISC_R_SUCCESS) goto unlock; @@ -5036,6 +5194,7 @@ dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, * Everything is ok so attach to the zone. */ zone->notify = newaddrs; + zone->notifydscp = newdscps; zone->notifykeynames = newnames; zone->notifycnt = count; unlock: @@ -5061,6 +5220,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, { isc_result_t result = ISC_R_SUCCESS; isc_sockaddr_t *newaddrs = NULL; + isc_dscp_t *newdscps = NULL; dns_name_t **newnames = NULL; isc_boolean_t *newok; unsigned int i; @@ -5095,8 +5255,9 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, zone->masterscnt * sizeof(isc_boolean_t)); zone->mastersok = NULL; } - clear_addresskeylist(&zone->masters, &zone->masterkeynames, - &zone->masterscnt, zone->mctx); + clear_addresskeylist(&zone->masters, &zone->masterdscps, + &zone->masterkeynames, &zone->masterscnt, + zone->mctx); /* * If count == 0, don't allocate any space for masters, mastersok or * keynames so internally, those pointers are NULL if count == 0 @@ -5119,8 +5280,9 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, /* * Now set up the masters and masterkey lists */ - result = set_addrkeylist(count, masters, &newaddrs, + result = set_addrkeylist(count, masters, &newaddrs, NULL, &newdscps, keynames, &newnames, zone->mctx); + INSIST(newdscps == NULL); if (result != ISC_R_SUCCESS) { isc_mem_put(zone->mctx, newok, count * sizeof(*newok)); goto unlock; @@ -5132,6 +5294,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, zone->curmaster = 0; zone->mastersok = newok; zone->masters = newaddrs; + zone->masterdscps = newdscps; zone->masterkeynames = newnames; zone->masterscnt = count; DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); @@ -9626,6 +9789,8 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { isc_sockaddr_t src; int timeout; isc_boolean_t have_notifysource = ISC_FALSE; + isc_boolean_t have_notifydscp = ISC_FALSE; + isc_dscp_t dscp = -1; notify = event->ev_arg; REQUIRE(DNS_NOTIFY_VALID(notify)); @@ -9692,16 +9857,23 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { result = dns_peer_getnotifysource(peer, &src); if (result == ISC_R_SUCCESS) have_notifysource = ISC_TRUE; + dns_peer_getnotifydscp(peer, &dscp); + if (dscp != -1) + have_notifydscp = ISC_TRUE; } } switch (isc_sockaddr_pf(¬ify->dst)) { case PF_INET: if (!have_notifysource) src = notify->zone->notifysrc4; + if (!have_notifydscp) + dscp = notify->zone->notifysrc4dscp; break; case PF_INET6: if (!have_notifysource) src = notify->zone->notifysrc6; + if (!have_notifydscp) + dscp = notify->zone->notifysrc6dscp; break; default: result = ISC_R_NOTIMPLEMENTED; @@ -9710,9 +9882,9 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { timeout = 15; if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_DIALNOTIFY)) timeout = 30; - result = dns_request_createvia2(notify->zone->view->requestmgr, - message, &src, ¬ify->dst, 0, key, - timeout * 3, timeout, + result = dns_request_createvia4(notify->zone->view->requestmgr, + message, &src, ¬ify->dst, dscp, + 0, key, timeout * 3, timeout, 0, notify->zone->task, notify_done, notify, ¬ify->request); if (result == ISC_R_SUCCESS) { @@ -10897,8 +11069,9 @@ soa_query(isc_task_t *task, isc_event_t *event) { isc_uint32_t options; isc_boolean_t cancel = ISC_TRUE; int timeout; - isc_boolean_t have_xfrsource, reqnsid; + isc_boolean_t have_xfrsource, have_xfrdscp, reqnsid; isc_uint16_t udpsize = SEND_BUFFER_SIZE; + isc_dscp_t dscp = -1; REQUIRE(DNS_ZONE_VALID(zone)); @@ -10957,7 +11130,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { } } - have_xfrsource = ISC_FALSE; + have_xfrsource = have_xfrdscp = ISC_FALSE; reqnsid = zone->view->requestnsid; if (zone->view->peers != NULL) { dns_peer_t *peer = NULL; @@ -10972,6 +11145,9 @@ soa_query(isc_task_t *task, isc_event_t *event) { &zone->sourceaddr); if (result == ISC_R_SUCCESS) have_xfrsource = ISC_TRUE; + dns_peer_gettransferdscp(peer, &dscp); + if (dscp != -1) + have_xfrdscp = ISC_TRUE; if (zone->view->resolver != NULL) udpsize = dns_resolver_getudpsize(zone->view->resolver); @@ -10987,8 +11163,13 @@ soa_query(isc_task_t *task, isc_event_t *event) { &zone->xfrsource4)) goto skip_master; zone->sourceaddr = zone->altxfrsource4; - } else if (!have_xfrsource) + if (!have_xfrdscp) + dscp = zone->altxfrsource4dscp; + } else if (!have_xfrsource) { zone->sourceaddr = zone->xfrsource4; + if (!have_xfrdscp) + dscp = zone->xfrsource4dscp; + } break; case PF_INET6: if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { @@ -10996,8 +11177,13 @@ soa_query(isc_task_t *task, isc_event_t *event) { &zone->xfrsource6)) goto skip_master; zone->sourceaddr = zone->altxfrsource6; - } else if (!have_xfrsource) + if (!have_xfrdscp) + dscp = zone->altxfrsource6dscp; + } else if (!have_xfrsource) { zone->sourceaddr = zone->xfrsource6; + if (!have_xfrdscp) + dscp = zone->xfrsource6dscp; + } break; default: result = ISC_R_NOTIMPLEMENTED; @@ -11019,11 +11205,11 @@ soa_query(isc_task_t *task, isc_event_t *event) { timeout = 15; if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) timeout = 30; - result = dns_request_createvia2(zone->view->requestmgr, message, + result = dns_request_createvia4(zone->view->requestmgr, message, &zone->sourceaddr, &zone->masteraddr, - options, key, timeout * 3, timeout, - zone->task, refresh_callback, zone, - &zone->request); + dscp, options, key, timeout * 3, + timeout, 0, zone->task, + refresh_callback, zone, &zone->request); if (result != ISC_R_SUCCESS) { zone_idetach(&dummy); zone_debuglog(zone, me, 1, @@ -11077,8 +11263,10 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { dns_tsigkey_t *key = NULL; dns_dbnode_t *node = NULL; int timeout; - isc_boolean_t have_xfrsource = ISC_FALSE, reqnsid; - isc_uint16_t udpsize = SEND_BUFFER_SIZE; + isc_boolean_t have_xfrsource = ISC_FALSE, have_xfrdscp = ISC_FALSE; + isc_boolean_t reqnsid; + isc_uint16_t udpsize = SEND_BUFFER_SIZE; + isc_dscp_t dscp = -1; REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(LOCKED_ZONE(zone)); @@ -11209,6 +11397,9 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { &zone->sourceaddr); if (result == ISC_R_SUCCESS) have_xfrsource = ISC_TRUE; + result = dns_peer_gettransferdscp(peer, &dscp); + if (dscp != -1) + have_xfrdscp = ISC_TRUE; if (zone->view->resolver != NULL) udpsize = dns_resolver_getudpsize(zone->view->resolver); @@ -11230,16 +11421,26 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { */ switch (isc_sockaddr_pf(&zone->masteraddr)) { case PF_INET: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { zone->sourceaddr = zone->altxfrsource4; - else if (!have_xfrsource) + if (!have_xfrdscp) + dscp = zone->altxfrsource4dscp; + } else if (!have_xfrsource) { zone->sourceaddr = zone->xfrsource4; + if (!have_xfrdscp) + dscp = zone->xfrsource4dscp; + } break; case PF_INET6: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { zone->sourceaddr = zone->altxfrsource6; - else if (!have_xfrsource) + if (!have_xfrdscp) + dscp = zone->altxfrsource6dscp; + } else if (!have_xfrsource) { zone->sourceaddr = zone->xfrsource6; + if (!have_xfrdscp) + dscp = zone->xfrsource6dscp; + } break; default: result = ISC_R_NOTIMPLEMENTED; @@ -11249,11 +11450,11 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { timeout = 15; if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) timeout = 30; - result = dns_request_createvia2(zone->view->requestmgr, message, + result = dns_request_createvia4(zone->view->requestmgr, message, &zone->sourceaddr, &zone->masteraddr, - DNS_REQUESTOPT_TCP, key, timeout * 3, - timeout, zone->task, stub_callback, - stub, &zone->request); + dscp, DNS_REQUESTOPT_TCP, key, + timeout * 3, timeout, 0, zone->task, + stub_callback, stub, &zone->request); if (result != ISC_R_SUCCESS) { zone_debuglog(zone, me, 1, "dns_request_createvia() failed: %s", @@ -13668,6 +13869,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { isc_sockaddr_t masteraddr; isc_time_t now; const char *soa_before = ""; + isc_dscp_t dscp = -1; UNUSED(task); @@ -13744,6 +13946,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { * Determine if we should attempt to sign the request with TSIG. */ result = ISC_R_NOTFOUND; + /* * First, look for a tsig key in the master statement, then * try for a server key. @@ -13764,13 +13967,28 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { isc_result_totext(result)); } + if (zone->masterdscps != NULL) + dscp = zone->masterdscps[zone->curmaster]; + LOCK_ZONE(zone); masteraddr = zone->masteraddr; sourceaddr = zone->sourceaddr; + switch (isc_sockaddr_pf(&masteraddr)) { + case PF_INET: + if (dscp == -1) + dscp = zone->xfrsource4dscp; + break; + case PF_INET6: + if (dscp == -1) + dscp = zone->xfrsource6dscp; + break; + default: + INSIST(0); + }; UNLOCK_ZONE(zone); INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr)); - result = dns_xfrin_create2(zone, xfrtype, &masteraddr, &sourceaddr, - zone->tsigkey, zone->mctx, + result = dns_xfrin_create3(zone, xfrtype, &masteraddr, &sourceaddr, + dscp, zone->tsigkey, zone->mctx, zone->zmgr->timermgr, zone->zmgr->socketmgr, zone->task, zone_xfrdone, &zone->xfr); if (result == ISC_R_SUCCESS) { @@ -13826,6 +14044,7 @@ static isc_result_t sendtomaster(dns_forward_t *forward) { isc_result_t result; isc_sockaddr_t src; + isc_dscp_t dscp = -1; LOCK_ZONE(forward->zone); @@ -13849,21 +14068,23 @@ sendtomaster(dns_forward_t *forward) { switch (isc_sockaddr_pf(&forward->addr)) { case PF_INET: src = forward->zone->xfrsource4; + dscp = forward->zone->xfrsource4dscp; break; case PF_INET6: src = forward->zone->xfrsource6; + dscp = forward->zone->xfrsource6dscp; break; default: result = ISC_R_NOTIMPLEMENTED; goto unlock; } - result = dns_request_createraw(forward->zone->view->requestmgr, - forward->msgbuf, - &src, &forward->addr, - DNS_REQUESTOPT_TCP, 15 /* XXX */, - forward->zone->task, - forward_callback, forward, - &forward->request); + result = dns_request_createraw4(forward->zone->view->requestmgr, + forward->msgbuf, + &src, &forward->addr, dscp, + DNS_REQUESTOPT_TCP, 15 /* XXX */, + 0, 0, forward->zone->task, + forward_callback, forward, + &forward->request); if (result == ISC_R_SUCCESS) { if (!ISC_LINK_LINKED(forward, link)) ISC_LIST_APPEND(forward->zone->forwards, forward, link); diff --git a/lib/isc/include/isc/namespace.h b/lib/isc/include/isc/namespace.h index b3a863e182..a8bccbcd60 100644 --- a/lib/isc/include/isc/namespace.h +++ b/lib/isc/include/isc/namespace.h @@ -124,6 +124,7 @@ #define isc_socket_gettype isc__socket_gettype #define isc_socket_isbound isc__socket_isbound #define isc_socket_ipv6only isc__socket_ipv6only +#define isc_socket_dscp isc__socket_dscp #define isc_socket_setname isc__socket_setname #define isc_socketmgr_getmaxsockets isc__socketmgr_getmaxsockets #define isc_socketmgr_setstats isc__socketmgr_setstats diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index 53291c656b..80e0351bcc 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -177,6 +177,7 @@ struct isc_socketevent { struct in6_pktinfo pktinfo; /*%< ipv6 pktinfo */ isc_uint32_t attributes; /*%< see below */ isc_eventdestructor_t destroy; /*%< original destructor */ + unsigned int dscp; /*%< UDP dscp value */ }; typedef struct isc_socket_newconnev isc_socket_newconnev_t; @@ -203,6 +204,7 @@ struct isc_socket_connev { * _TIMESTAMP: The timestamp member is valid. * _PKTINFO: The pktinfo member is valid. * _MULTICAST: The UDP packet was received via a multicast transmission. + * _DSCP: The UDP DSCP value is valid. */ #define ISC_SOCKEVENTATTR_ATTACHED 0x80000000U /* internal */ #define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */ @@ -210,6 +212,7 @@ struct isc_socket_connev { #define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */ #define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */ #define ISC_SOCKEVENTATTR_MULTICAST 0x00080000U /* public */ +#define ISC_SOCKEVENTATTR_DSCP 0x00040000U /* public */ /*@}*/ #define ISC_SOCKEVENT_ANYEVENT (0) @@ -314,6 +317,7 @@ typedef struct isc_socketmethods { isc_result_t (*dup)(isc_socket_t *socket, isc_socket_t **socketp); int (*getfd)(isc_socket_t *socket); + void (*dscp)(isc_socket_t *socket, isc_dscp_t dscp); } isc_socketmethods_t; /*% @@ -1073,6 +1077,24 @@ isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes); */ /*@}*/ +void +isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp); +/*%< + * Sets the Differentiated Services Code Point (DSCP) field for packets + * transmitted on this socket. If 'dscp' is -1, return immediately. + * + * Requires: + *\li 'sock' is a valid socket. + */ + +isc_socketevent_t * +isc_socket_socketevent(isc_mem_t *mctx, void *sender, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg); +/*%< + * Get a isc_socketevent_t to be used with isc_socket_sendto2(), etc. + */ + void isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active); diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index a082dd59e1..bbd664434d 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -50,6 +50,7 @@ typedef struct isc_buffer isc_buffer_t; /*%< Buffer */ typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */ typedef struct isc_constregion isc_constregion_t; /*%< Const region */ typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */ +typedef isc_int16_t isc_dscp_t; /*%< Diffserv code point */ typedef struct isc_entropy isc_entropy_t; /*%< Entropy */ typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */ typedef struct isc_event isc_event_t; /*%< Event */ diff --git a/lib/isc/socket_api.c b/lib/isc/socket_api.c index 1fba3e0ac1..3c6422ad73 100644 --- a/lib/isc/socket_api.c +++ b/lib/isc/socket_api.c @@ -202,6 +202,13 @@ isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { sock->methods->ipv6only(sock, yes); } +void +isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + sock->methods->dscp(sock, dscp); +} + isc_sockettype_t isc_socket_gettype(isc_socket_t *sock) { REQUIRE(ISCAPI_SOCKET_VALID(sock)); diff --git a/lib/isc/tests/Makefile.in b/lib/isc/tests/Makefile.in index 89e115769c..cc5dca0ee4 100644 --- a/lib/isc/tests/Makefile.in +++ b/lib/isc/tests/Makefile.in @@ -37,13 +37,13 @@ LIBS = @LIBS@ @ATFLIBS@ OBJS = isctest.@O@ SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \ sockaddr_test.c symtab_test.c task_test.c queue_test.c \ - parse_test.c pool_test.c regex_test.c + parse_test.c pool_test.c regex_test.c socket_test.c SUBDIRS = TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \ sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \ queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \ - regex_test@EXEEXT@ + regex_test@EXEEXT@ socket_test@EXEEXT@ @BIND9_MAKE_RULES@ diff --git a/lib/isc/tests/isctest.c b/lib/isc/tests/isctest.c index 41b09fce6e..d8ef00996a 100644 --- a/lib/isc/tests/isctest.c +++ b/lib/isc/tests/isctest.c @@ -91,7 +91,7 @@ create_managers() { CHECK(isc_socketmgr_create(mctx, &socketmgr)); return (ISC_R_SUCCESS); - cleanup: + cleanup: cleanup_managers(); return (result); } diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c index 724d79df2b..f316c61027 100644 --- a/lib/isc/tests/socket_test.c +++ b/lib/isc/tests/socket_test.c @@ -30,17 +30,38 @@ #include "../task_p.h" #include "isctest.h" +static isc_boolean_t recv_dscp; +static unsigned int recv_dscp_value; + /* * Helper functions */ + typedef struct { isc_boolean_t done; isc_result_t result; + isc_socket_t *socket; } completion_t; static void completion_init(completion_t *completion) { completion->done = ISC_FALSE; + completion->socket = NULL; +} + +static void +accept_done(isc_task_t *task, isc_event_t *event) { + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; + completion_t *completion = event->ev_arg; + + UNUSED(task); + + completion->result = nevent->result; + completion->done = ISC_TRUE; + if (completion->result == ISC_R_SUCCESS) + completion->socket = nevent->newsocket; + + isc_event_free(&event); } static void @@ -53,6 +74,11 @@ event_done(isc_task_t *task, isc_event_t *event) { dev = (isc_socketevent_t *) event; completion->result = dev->result; completion->done = ISC_TRUE; + if ((dev->attributes & ISC_SOCKEVENTATTR_DSCP) != 0) { + recv_dscp = ISC_TRUE; + recv_dscp_value = dev->dscp;; + } else + recv_dscp = ISC_FALSE; isc_event_free(&event); } @@ -71,6 +97,49 @@ waitfor(completion_t *completion) { return (ISC_R_FAILURE); } +#if 0 +static isc_result_t +waitfor(completion_t *completion) { + int i = 0; + while (!completion->done && i++ < 5000) { + waitbody(); + } + if (completion->done) + return (ISC_R_SUCCESS); + return (ISC_R_FAILURE); +} +#endif + +static void +waitbody() { +#ifndef ISC_PLATFORM_USETHREADS + struct timeval tv; + isc_socketwait_t *swait = NULL; + + while (isc__taskmgr_ready(taskmgr)) + isc__taskmgr_dispatch(taskmgr); + if (socketmgr != NULL) { + tv.tv_sec = 0; + tv.tv_usec = 1000 ; + if (isc__socketmgr_waitevents(socketmgr, &tv, &swait) > 0) + isc__socketmgr_dispatch(socketmgr, swait); + } else +#endif + isc_test_nap(1000); +} + +static isc_result_t +waitfor2(completion_t *c1, completion_t *c2) { + int i = 0; + + while (!(c1->done && c2->done) && i++ < 5000) { + waitbody(); + } + if (c1->done && c2->done) + return (ISC_R_SUCCESS); + return (ISC_R_FAILURE); +} + /* * Individual unit tests */ @@ -243,13 +312,454 @@ ATF_TC_BODY(udp_dup, tc) { isc_test_end(); } +/* Test TCP sendto/recv (IPv4) */ +ATF_TC(udp_dscp_v4); +ATF_TC_HEAD(udp_dscp_v4, tc) { + atf_tc_set_md_var(tc, "descr", "UDP DSCP IPV4"); +} +ATF_TC_BODY(udp_dscp_v4, tc) { + isc_result_t result; + isc_sockaddr_t addr1, addr2; + struct in_addr in; + isc_socket_t *s1 = NULL, *s2 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion; + isc_region_t r; + isc_socketevent_t *socketevent; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: 127.0.0.1/5444 and 127.0.0.1/5445, talking to + * each other. + */ + in.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&addr1, &in, 5444); + isc_sockaddr_fromin(&addr2, &in, 5445); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + result = isc_task_create(taskmgr, 0, &task); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + + socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE, + event_done, &completion); + ATF_REQUIRE(socketevent != NULL); + + if ((isc_net_probedscp() & ISC_NET_DSCPPKTV4) != 0) { + socketevent->dscp = 056; /* EF */ + socketevent->attributes |= ISC_SOCKEVENTATTR_DSCP; + } else if ((isc_net_probedscp() & ISC_NET_DSCPSETV4) != 0) { + isc_socket_dscp(s1, 056); /* EF */ + socketevent->dscp = 0; + socketevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; + } + + recv_dscp = ISC_FALSE; + recv_dscp_value = 0; + + result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + + if ((isc_net_probedscp() & ISC_NET_DSCPRECVV4) != 0) { + ATF_CHECK(recv_dscp); + ATF_CHECK_EQ(recv_dscp_value, 056); + } else + ATF_CHECK(!recv_dscp); + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + + isc_test_end(); +} + +/* Test TCP sendto/recv (IPv4) */ +ATF_TC(udp_dscp_v6); +ATF_TC_HEAD(udp_dscp_v6, tc) { + atf_tc_set_md_var(tc, "descr", "udp dscp ipv6"); +} +ATF_TC_BODY(udp_dscp_v6, tc) { + isc_result_t result; + isc_sockaddr_t addr1, addr2; + struct in6_addr in6; + isc_socket_t *s1 = NULL, *s2 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion; + isc_region_t r; + isc_socketevent_t *socketevent; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: ::1/5444 and ::1/5445, talking to + * each other. + */ + inet_pton(AF_INET6, "::1", &in6.s6_addr); + isc_sockaddr_fromin6(&addr1, &in6, 5444); + isc_sockaddr_fromin6(&addr2, &in6, 5445); + + result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_udp, + &s1); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_udp, + &s2); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + result = isc_task_create(taskmgr, 0, &task); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + + socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE, + event_done, &completion); + ATF_REQUIRE(socketevent != NULL); + + if ((isc_net_probedscp() & ISC_NET_DSCPPKTV6) != 0) { + socketevent->dscp = 056; /* EF */ + socketevent->attributes = ISC_SOCKEVENTATTR_DSCP; + } else if ((isc_net_probedscp() & ISC_NET_DSCPSETV6) != 0) + isc_socket_dscp(s1, 056); /* EF */ + + recv_dscp = ISC_FALSE; + recv_dscp_value = 0; + + result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + if ((isc_net_probedscp() & ISC_NET_DSCPRECVV6) != 0) { + ATF_CHECK(recv_dscp); + ATF_CHECK_EQ(recv_dscp_value, 056); + } else + ATF_CHECK(!recv_dscp); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + + isc_test_end(); +} + +/* Test TCP sendto/recv (IPv4) */ +ATF_TC(tcp_dscp_v4); +ATF_TC_HEAD(tcp_dscp_v4, tc) { + atf_tc_set_md_var(tc, "descr", "tcp dscp ipv4"); +} +ATF_TC_BODY(tcp_dscp_v4, tc) { + isc_result_t result; + isc_sockaddr_t addr1; + struct in_addr in; + isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion, completion2; + isc_region_t r; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: 127.0.0.1/5444, talking to each other. + */ + in.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&addr1, &in, 5444); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp, &s1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_listen(s1, 3); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp, &s2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + completion_init(&completion2); + result = isc_socket_accept(s1, task, accept_done, &completion2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + completion_init(&completion); + result = isc_socket_connect(s2, &addr1, task, event_done, &completion); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + waitfor2(&completion, &completion2); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK(completion2.done); + ATF_CHECK_EQ(completion2.result, ISC_R_SUCCESS); + s3 = completion2.socket; + + isc_socket_dscp(s2, 056); /* EF */ + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + recv_dscp = ISC_FALSE; + recv_dscp_value = 0; + + completion_init(&completion); + result = isc_socket_sendto(s2, &r, task, event_done, &completion, + NULL, NULL); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s3, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + + if ((isc_net_probedscp() & ISC_NET_DSCPRECVV4) != 0) { + if (recv_dscp) + ATF_CHECK_EQ(recv_dscp_value, 056); + } else + ATF_CHECK(!recv_dscp); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + isc_socket_detach(&s3); + + isc_test_end(); +} + +/* Test TCP sendto/recv (IPv6) */ +ATF_TC(tcp_dscp_v6); +ATF_TC_HEAD(tcp_dscp_v6, tc) { + atf_tc_set_md_var(tc, "descr", "tcp dscp ipv6"); +} +ATF_TC_BODY(tcp_dscp_v6, tc) { + isc_result_t result; + isc_sockaddr_t addr1; + struct in6_addr in6; + isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion, completion2; + isc_region_t r; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: ::1/5444, talking to each other. + */ + inet_pton(AF_INET6, "::1", &in6.s6_addr); + isc_sockaddr_fromin6(&addr1, &in6, 5444); + + result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_tcp, + &s1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_listen(s1, 3); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_create(socketmgr, PF_INET6, isc_sockettype_tcp, + &s2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + completion_init(&completion2); + result = isc_socket_accept(s1, task, accept_done, &completion2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + completion_init(&completion); + result = isc_socket_connect(s2, &addr1, task, event_done, &completion); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + waitfor2(&completion, &completion2); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK(completion2.done); + ATF_CHECK_EQ(completion2.result, ISC_R_SUCCESS); + s3 = completion2.socket; + + isc_socket_dscp(s2, 056); /* EF */ + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + recv_dscp = ISC_FALSE; + recv_dscp_value = 0; + + completion_init(&completion); + result = isc_socket_sendto(s2, &r, task, event_done, &completion, + NULL, NULL); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s3, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + + if ((isc_net_probedscp() & ISC_NET_DSCPRECVV6) != 0) { + /* + * IPV6_RECVTCLASS is undefined for TCP however + * if we do get it should be the the value we set. + */ + if (recv_dscp) + ATF_CHECK_EQ(recv_dscp_value, 056); + } else + ATF_CHECK(!recv_dscp); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + isc_socket_detach(&s3); + + isc_test_end(); +} + +ATF_TC(net_probedscp); +ATF_TC_HEAD(net_probedscp, tc) { + atf_tc_set_md_var(tc, "descr", "probe dscp capabilities"); +} +ATF_TC_BODY(net_probedscp, tc) { + unsigned int n; + + UNUSED(tc); + + n = isc_net_probedscp(); + ATF_CHECK((n & ~ISC_NET_DSCPALL) == 0); + + /* ISC_NET_DSCPSETV4 MUST be set if any is set. */ + if (n & (ISC_NET_DSCPSETV4|ISC_NET_DSCPPKTV4|ISC_NET_DSCPRECVV4)) + ATF_CHECK_MSG((n & ISC_NET_DSCPSETV4) != 0, + "IPv4:%s%s%s\n", + (n & ISC_NET_DSCPSETV4) ? " set" : " none", + (n & ISC_NET_DSCPPKTV4) ? " packet" : "", + (n & ISC_NET_DSCPRECVV4) ? " receive" : ""); + + /* ISC_NET_DSCPSETV6 MUST be set if any is set. */ + if (n & (ISC_NET_DSCPSETV6|ISC_NET_DSCPPKTV4|ISC_NET_DSCPRECVV4)) + ATF_CHECK_MSG((n & ISC_NET_DSCPSETV6) != 0, + "IPv6:%s%s%s\n", + (n & ISC_NET_DSCPSETV6) ? " set" : " none", + (n & ISC_NET_DSCPPKTV6) ? " packet" : "", + (n & ISC_NET_DSCPRECVV6) ? " receive" : ""); + +#if 0 + fprintf(stdout, "IPv4:%s%s%s\n", + (n & ISC_NET_DSCPSETV4) ? " set" : "none", + (n & ISC_NET_DSCPPKTV4) ? " packet" : "", + (n & ISC_NET_DSCPRECVV4) ? " receive" : ""); + + printf(stdout, "IPv6:%s%s%s\n", + (n & ISC_NET_DSCPSETV6) ? " set" : "none", + (n & ISC_NET_DSCPPKTV6) ? " packet" : "", + (n & ISC_NET_DSCPRECVV6) ? " receive" : ""); +#endif +} + /* * Main */ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, udp_sendto); ATF_TP_ADD_TC(tp, udp_dup); + ATF_TP_ADD_TC(tp, tcp_dscp_v4); + ATF_TP_ADD_TC(tp, tcp_dscp_v6); + ATF_TP_ADD_TC(tp, udp_dscp_v4); + ATF_TP_ADD_TC(tp, udp_dscp_v6); + ATF_TP_ADD_TC(tp, net_probedscp); return (atf_no_error()); } - diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h index efa67c223b..93b8497088 100644 --- a/lib/isc/unix/include/isc/net.h +++ b/lib/isc/unix/include/isc/net.h @@ -324,6 +324,21 @@ isc_net_probeunix(void); * Returns whether UNIX domain sockets are supported. */ +#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */ +#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */ +#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */ +#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */ +#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */ +#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */ +#define ISC_NET_DSCPALL 0x3f /* All valid flags */ + +unsigned int +isc_net_probedscp(void); +/*%< + * Probe the level of DSCP support. + */ + + isc_result_t isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high); /*%< diff --git a/lib/isc/unix/net.c b/lib/isc/unix/net.c index 1fedbc438d..9cca372f11 100644 --- a/lib/isc/unix/net.c +++ b/lib/isc/unix/net.c @@ -34,11 +34,16 @@ #include #include #include +#include #include #include #include #include +#ifndef ISC_SOCKADDR_LEN_T +#define ISC_SOCKADDR_LEN_T unsigned int +#endif + /*% * Definitions about UDP port range specification. This is a total mess of * portability variants: some use sysctl (but the sysctl names vary), some use @@ -111,12 +116,14 @@ static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT; #endif /* ISC_PLATFORM_HAVEIPV6 */ static isc_once_t once = ISC_ONCE_INIT; +static isc_once_t once_dscp = ISC_ONCE_INIT; static isc_result_t ipv4_result = ISC_R_NOTFOUND; static isc_result_t ipv6_result = ISC_R_NOTFOUND; static isc_result_t unix_result = ISC_R_NOTFOUND; static isc_result_t ipv6only_result = ISC_R_NOTFOUND; static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND; +static unsigned int dscp_result = 0; static isc_result_t try_proto(int domain) { @@ -397,6 +404,259 @@ isc_net_probe_ipv6pktinfo(void) { return (ipv6pktinfo_result); } +static inline ISC_SOCKADDR_LEN_T +cmsg_len(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_LEN + return (CMSG_LEN(len)); +#else + ISC_SOCKADDR_LEN_T hdrlen; + + /* + * Cast NULL so that any pointer arithmetic performed by CMSG_DATA + * is correct. + */ + hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL)); + return (hdrlen + len); +#endif +} + +static inline ISC_SOCKADDR_LEN_T +cmsg_space(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_SPACE + return (CMSG_SPACE(len)); +#else + struct msghdr msg; + struct cmsghdr *cmsgp; + /* + * XXX: The buffer length is an ad-hoc value, but should be enough + * in a practical sense. + */ + char dummybuf[sizeof(struct cmsghdr) + 1024]; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = dummybuf; + msg.msg_controllen = sizeof(dummybuf); + + cmsgp = (struct cmsghdr *)dummybuf; + cmsgp->cmsg_len = cmsg_len(len); + + cmsgp = CMSG_NXTHDR(&msg, cmsgp); + if (cmsgp != NULL) + return ((char *)cmsgp - (char *)msg.msg_control); + else + return (0); +#endif +} + +#ifdef ISC_NET_BSD44MSGHDR +static isc_boolean_t +cmsgsend(int s, int level, int type, struct addrinfo *res) { + char strbuf[ISC_STRERRORSIZE]; + struct sockaddr_storage ss; + ISC_SOCKADDR_LEN_T len = sizeof(ss); + struct msghdr msg; + union { + struct cmsghdr h; + unsigned char b[256]; + } control; + struct cmsghdr *cmsgp; + int dscp = 46; + struct iovec iovec = { &iovec, sizeof(iovec) }; + + if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "bind: %s", strbuf); + return (ISC_FALSE); + } + + if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "getsockname: %s", strbuf); + return (ISC_FALSE); + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (struct sockaddr *)&ss; + msg.msg_namelen = len; + msg.msg_iov = &iovec; + msg.msg_iovlen = 1; + msg.msg_control = (void*)&control; + msg.msg_controllen = cmsg_space(sizeof(int)); + msg.msg_flags = 0; + + cmsgp = msg.msg_control; + cmsgp->cmsg_level = level; + cmsgp->cmsg_type = type; + if (cmsgp->cmsg_type == IP_TOS) { + cmsgp->cmsg_len = cmsg_len(sizeof(char)); + *(unsigned char*)CMSG_DATA(cmsgp) = dscp; + } else { + cmsgp->cmsg_len = cmsg_len(sizeof(dscp)); + memcpy(CMSG_DATA(cmsgp), &dscp, sizeof(dscp)); + } + + if (sendmsg(s, &msg, 0) < 0) { + int debug = ISC_LOG_DEBUG(10); +#ifdef ENOPROTOOPT + if (errno != ENOPROTOOPT && errno != EINVAL) + debug = ISC_LOG_NOTICE; +#endif + isc__strerror(errno, strbuf, sizeof(strbuf)); + if (debug != ISC_LOG_NOTICE) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "sendmsg: %s", strbuf); + } else { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "sendmsg() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + return (ISC_FALSE); + } + + return (ISC_TRUE); +} +#endif + +static void +try_dscp_v4(void) { +#ifdef IP_TOS + char strbuf[ISC_STRERRORSIZE]; + struct addrinfo hints, *res0; + int s, dscp = 0, n; +#ifdef IP_RECVTOS + int on = 1; +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_PASSIVE; + + n = getaddrinfo("127.0.0.1", NULL, &hints, &res0); + if (n != 0 || res0 == NULL) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "getaddrinfo(127.0.0.1): %s", gai_strerror(n)); + return; + } + + s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol); + if (s == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "socket: %s", strbuf); + freeaddrinfo(res0); + close(s); + return; + } + if (setsockopt(s, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) == 0) + dscp_result |= ISC_NET_DSCPSETV4; + +#ifdef IP_RECVTOS + on = 1; + if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) == 0) + dscp_result |= ISC_NET_DSCPRECVV4; +#endif +#ifdef ISC_NET_BSD44MSGHDR +#ifndef ISC_CMSG_IP_TOS +#ifdef __APPLE__ +#define ISC_CMSG_IP_TOS 0 /* As of 10.8.2. */ +#else +#define ISC_CMSG_IP_TOS 1 +#endif +#endif +#if ISC_CMSG_IP_TOS + if (cmsgsend(s, IPPROTO_IP, IP_TOS, res0)) + dscp_result |= ISC_NET_DSCPPKTV4; +#endif +#endif + freeaddrinfo(res0); + close(s); +#endif +} + +static void +try_dscp_v6(void) { +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +#ifdef IPV6_TCLASS + char strbuf[ISC_STRERRORSIZE]; + struct addrinfo hints, *res0; + int s, dscp = 0, n; +#if defined(IPV6_RECVTCLASS) + int on = 1; +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_PASSIVE; + + n = getaddrinfo("::1", NULL, &hints, &res0); + if (n != 0 || res0 == NULL) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "getaddrinfo(::1): %s", gai_strerror(n)); + return; + } + + s = socket(res0->ai_family, res0->ai_socktype, res0->ai_protocol); + if (s == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(10), + "socket: %s", strbuf); + freeaddrinfo(res0); + return; + } + if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &dscp, sizeof(dscp)) == 0) + dscp_result |= ISC_NET_DSCPSETV6; + +#ifdef IPV6_RECVTCLASS + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)) == 0) + dscp_result |= ISC_NET_DSCPRECVV6; +#endif +#ifdef ISC_NET_BSD44MSGHDR + if (cmsgsend(s, IPPROTO_IPV6, IPV6_TCLASS, res0)) + dscp_result |= ISC_NET_DSCPPKTV6; +#endif + freeaddrinfo(res0); + close(s); +#endif +#endif +#endif +} + +static void +try_dscp() { + try_dscp_v4(); + try_dscp_v6(); +} + +static void +initialize_dscp() { + RUNTIME_CHECK(isc_once_do(&once_dscp, try_dscp) == ISC_R_SUCCESS); +} + +unsigned int +isc_net_probedscp(void) { + initialize_dscp(); + return (dscp_result); +} + #if defined(USE_SYSCTL_PORTRANGE) #if defined(HAVE_SYSCTLBYNAME) static isc_result_t diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index f2efd48bb4..f4c0c48b83 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -127,6 +127,13 @@ struct isc_socketwait { #endif /* USE_KQUEUE */ #endif /* !USE_WATCHER_THREAD */ +/* + * Set by the -T dscp option on the command line. If set to a value + * other than -1, we check to make sure DSCP values match it, and + * assert if not. + */ +int isc_dscp_check_value = -1; + /*% * Maximum number of allowable open sockets. This is also the maximum * allowable socket file descriptor. @@ -352,6 +359,7 @@ struct isc__socket { isc_sockfdwatch_t fdwatchcb; int fdwatchflags; isc_task_t *fdwatchtask; + int dscp; }; #define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g') @@ -455,6 +463,7 @@ static void build_msghdr_recv(isc__socket_t *, isc_socketevent_t *, #ifdef USE_WATCHER_THREAD static isc_boolean_t process_ctlfd(isc__socketmgr_t *manager); #endif +static void setdscp(isc__socket_t *sock, isc_dscp_t dscp); /*% * The following can be either static or public, depending on build environment. @@ -511,6 +520,11 @@ isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region, isc_task_t *task, isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, isc_socketevent_t *event, unsigned int flags); +isc_socketevent_t * +isc_socket_socketevent(isc_mem_t *mctx, void *sender, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg); + ISC_SOCKETFUNC_SCOPE void isc__socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active); ISC_SOCKETFUNC_SCOPE isc_result_t @@ -542,6 +556,8 @@ ISC_SOCKETFUNC_SCOPE isc_boolean_t isc__socket_isbound(isc_socket_t *sock); ISC_SOCKETFUNC_SCOPE void isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes); +ISC_SOCKETFUNC_SCOPE void +isc__socket_dscp(isc_socket_t *sock, isc_dscp_t dscp); #ifdef BIND9 #ifdef HAVE_LIBXML2 ISC_SOCKETFUNC_SCOPE void @@ -590,7 +606,8 @@ static struct { isc__socket_ipv6only, isc__socket_fdwatchpoke, isc__socket_dup, - isc__socket_getfd + isc__socket_getfd, + isc__socket_dscp } #ifndef BIND9 , @@ -1308,6 +1325,25 @@ process_cmsg(isc__socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { } #endif +#ifdef IPV6_TCLASS + if (cmsgp->cmsg_level == IPPROTO_IPV6 + && cmsgp->cmsg_type == IPV6_TCLASS) { + dev->dscp = *(int *)CMSG_DATA(cmsgp); + dev->dscp >>= 2; + dev->attributes |= ISC_SOCKEVENTATTR_DSCP; + goto next; + } +#endif + +#ifdef IP_TOS + if (cmsgp->cmsg_level == IPPROTO_IP + && cmsgp->cmsg_type == IP_TOS) { + dev->dscp = (int) *(uint8_t *)CMSG_DATA(cmsgp); + dev->dscp >>= 2; + dev->attributes |= ISC_SOCKEVENTATTR_DSCP; + goto next; + } +#endif next: cmsgp = CMSG_NXTHDR(msg, cmsgp); } @@ -1337,6 +1373,9 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_region_t used; size_t write_count; size_t skip_count; +#ifdef ISC_NET_BSD44MSGHDR + struct cmsghdr *cmsgp; +#endif memset(msg, 0, sizeof(*msg)); @@ -1409,7 +1448,6 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, #if defined(IPV6_USE_MIN_MTU) int use_min_mtu = 1; /* -1, 0, 1 */ #endif - struct cmsghdr *cmsgp; struct in6_pktinfo *pktinfop; socket_log(sock, NULL, TRACE, @@ -1444,6 +1482,83 @@ build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, memcpy(CMSG_DATA(cmsgp), &use_min_mtu, sizeof(use_min_mtu)); #endif } +#ifdef BIND9 + if (isc_dscp_check_value != -1) { + if (sock->type == isc_sockettype_udp) + INSIST((int)dev->dscp == isc_dscp_check_value); + if (sock->type == isc_sockettype_tcp) + INSIST(sock->dscp == isc_dscp_check_value); + } + + if ((sock->type == isc_sockettype_udp) + && ((dev->attributes & ISC_SOCKEVENTATTR_DSCP) != 0)) { + int dscp = (dev->dscp << 2) & 0xff; + +#ifdef IP_TOS + if (sock->pf == AF_INET && + ((isc_net_probedscp() & ISC_NET_DSCPPKTV4) != 0)) + { + cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + msg->msg_controllen); + msg->msg_control = (void *)sock->sendcmsgbuf; + msg->msg_controllen += cmsg_space(sizeof(dscp)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + + cmsgp->cmsg_level = IPPROTO_IP; + cmsgp->cmsg_type = IP_TOS; + cmsgp->cmsg_len = cmsg_len(sizeof(char)); + *(unsigned char*)CMSG_DATA(cmsgp) = dscp; + } else if (sock->pf == AF_INET) { + if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS, + (void *)&dscp, sizeof(int)) < 0) + { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IP_TOS, %.02x)" + " %s: %s", + sock->fd, dscp >> 2, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } +#endif +#ifdef IPPROTO_IPV6 + if (sock->pf == AF_INET6 && + ((isc_net_probedscp() & ISC_NET_DSCPPKTV6) != 0)) + { + cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + msg->msg_controllen); + msg->msg_control = (void *)sock->sendcmsgbuf; + msg->msg_controllen += cmsg_space(sizeof(dscp)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_TCLASS; + cmsgp->cmsg_len = cmsg_len(sizeof(dscp)); + memcpy(CMSG_DATA(cmsgp), &dscp, sizeof(dscp)); + } else if (sock->pf == AF_INET6) { + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS, + (void *)&dscp, sizeof(int)) < 0) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_TCLASS, " + "%.02x) %s: %s", + sock->fd, dscp >> 2, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } +#endif + } +#endif #endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */ #else /* ISC_NET_BSD44MSGHDR */ msg->msg_accrights = NULL; @@ -1573,10 +1688,8 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, msg->msg_controllen = 0; msg->msg_flags = 0; #if defined(USE_CMSG) - if (sock->type == isc_sockettype_udp) { - msg->msg_control = sock->recvcmsgbuf; - msg->msg_controllen = sock->recvcmsgbuflen; - } + msg->msg_control = sock->recvcmsgbuf; + msg->msg_controllen = sock->recvcmsgbuflen; #endif /* USE_CMSG */ #else /* ISC_NET_BSD44MSGHDR */ msg->msg_accrights = NULL; @@ -1612,14 +1725,14 @@ destroy_socketevent(isc_event_t *event) { } static isc_socketevent_t * -allocate_socketevent(isc__socket_t *sock, isc_eventtype_t eventtype, - isc_taskaction_t action, const void *arg) +allocate_socketevent(isc_mem_t *mctx, void *sender, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg) { isc_socketevent_t *ev; - ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, - sock, eventtype, - action, arg, + ev = (isc_socketevent_t *)isc_event_allocate(mctx, sender, + eventtype, action, arg, sizeof(*ev)); if (ev == NULL) @@ -1634,6 +1747,7 @@ allocate_socketevent(isc__socket_t *sock, isc_eventtype_t eventtype, ev->attributes = 0; ev->destroy = ev->ev_destroy; ev->ev_destroy = destroy_socketevent; + ev->dscp = 0; return (ev); } @@ -1801,8 +1915,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { * If there are control messages attached, run through them and pull * out the interesting bits. */ - if (sock->type == isc_sockettype_udp) - process_cmsg(sock, &msghdr, dev); + process_cmsg(sock, &msghdr, dev); /* * update the buffers (if any) and the i/o count @@ -2095,6 +2208,7 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, sock->manager = manager; sock->type = type; sock->fd = -1; + sock->dscp = -1; sock->dupped = 0; sock->statsindex = NULL; @@ -2112,6 +2226,9 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, #endif #if defined(USE_CMSG) && defined(SO_TIMESTAMP) cmsgbuflen += cmsg_space(sizeof(struct timeval)); +#endif +#if defined(USE_CMSG) && (defined(IPV6_TCLASS) || defined(IP_TOS)) + cmsgbuflen += cmsg_space(sizeof(int)); #endif sock->recvcmsgbuflen = cmsgbuflen; if (sock->recvcmsgbuflen != 0U) { @@ -2132,6 +2249,9 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, */ cmsgbuflen += cmsg_space(sizeof(int)); #endif +#endif +#if defined(USE_CMSG) && (defined(IP_TOS) || defined(IPV6_TCLASS)) + cmsgbuflen += cmsg_space(sizeof(int)); #endif sock->sendcmsgbuflen = cmsgbuflen; if (sock->sendcmsgbuflen != 0U) { @@ -2589,6 +2709,32 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, } #endif } +#ifdef IPV6_RECVTCLASS + if ((sock->pf == AF_INET6) + && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVTCLASS, + (void *)&on, sizeof(on)) < 0)) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_RECVTCLASS) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + } +#endif +#ifdef IP_RECVTOS + if ((sock->pf == AF_INET) + && (setsockopt(sock->fd, IPPROTO_IP, IP_RECVTOS, + (void *)&on, sizeof(on)) < 0)) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IP_RECVTOS) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + } +#endif #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */ setup_done: @@ -3339,6 +3485,12 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { */ use_min_mtu(NEWCONNSOCK(dev)); + /* + * Ensure DSCP settings are inherited across accept. + */ + if (sock->dscp != -1) + setdscp(NEWCONNSOCK(dev), sock->dscp); + /* * Save away the remote address */ @@ -4617,7 +4769,8 @@ isc__socket_recvv(isc_socket_t *sock0, isc_bufferlist_t *buflist, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_RECVDONE, action, arg); if (dev == NULL) return (ISC_R_NOMEMORY); @@ -4663,7 +4816,8 @@ isc__socket_recv(isc_socket_t *sock0, isc_region_t *region, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_RECVDONE, action, arg); if (dev == NULL) return (ISC_R_NOMEMORY); @@ -4822,7 +4976,8 @@ isc__socket_sendto(isc_socket_t *sock0, isc_region_t *region, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_SENDDONE, action, arg); if (dev == NULL) return (ISC_R_NOMEMORY); @@ -4862,7 +5017,8 @@ isc__socket_sendtov(isc_socket_t *sock0, isc_bufferlist_t *buflist, iocount = isc_bufferlist_usedcount(buflist); REQUIRE(iocount > 0); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_SENDDONE, action, arg); if (dev == NULL) return (ISC_R_NOMEMORY); @@ -4897,7 +5053,7 @@ isc__socket_sendto2(isc_socket_t *sock0, isc_region_t *region, event->region = *region; event->n = 0; event->offset = 0; - event->attributes = 0; + event->attributes &= ~ISC_SOCKEVENTATTR_ATTACHED; return (socket_send(sock, event, task, address, pktinfo, flags)); } @@ -5811,6 +5967,84 @@ isc__socket_ipv6only(isc_socket_t *sock0, isc_boolean_t yes) { #endif } +static void +setdscp(isc__socket_t *sock, isc_dscp_t dscp) { + + sock->dscp = dscp; + +#if defined(IP_TOS) || defined(IPV6_TCLASS) + dscp <<= 2; +#endif + +#ifdef IP_TOS + if (sock->pf == AF_INET) { + if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS, + (void *)&dscp, sizeof(int)) < 0) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IP_TOS, %.02x) " + "%s: %s", sock->fd, dscp >> 2, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } +#endif +#ifdef IPV6_TCLASS + if (sock->pf == AF_INET6) { + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS, + (void *)&dscp, sizeof(int)) < 0) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_TCLASS, %.02x) " + "%s: %s", sock->fd, dscp >> 2, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } +#endif +} + +ISC_SOCKETFUNC_SCOPE void +isc__socket_dscp(isc_socket_t *sock0, isc_dscp_t dscp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(dscp < 0x40); + +#if !defined(IP_TOS) && !defined(IPV6_TCLASS) + UNUSED(dscp); +#else + if (dscp < 0) + return; + + if (isc_dscp_check_value != -1) + INSIST(dscp == isc_dscp_check_value); +#endif + + +#ifdef notyet + REQUIRE(!sock->dupped); +#endif + + setdscp(sock, dscp); +} + +isc_socketevent_t * +isc_socket_socketevent(isc_mem_t *mctx, void *sender, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg) +{ + return (allocate_socketevent(mctx, sender, eventtype, action, arg)); +} + #ifndef USE_WATCHER_THREAD /* * In our assumed scenario, we can simply use a single static object. diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h index 43e424d865..a6701c590d 100644 --- a/lib/isc/win32/include/isc/net.h +++ b/lib/isc/win32/include/isc/net.h @@ -269,6 +269,20 @@ isc_net_probeunix(void); * ISC_R_NOTFOUND */ +#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */ +#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */ +#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */ +#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */ +#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */ +#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */ +#define ISC_NET_DSCPALL 0x3f /* All valid flags */ + +unsigned int +isc_net_probedscp(void); +/*%< + * Probe the level of DSCP support. + */ + isc_result_t isc_net_probe_ipv6only(void); /* diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def index 24341b8b43..18c093c571 100644 --- a/lib/isc/win32/libisc.def +++ b/lib/isc/win32/libisc.def @@ -110,6 +110,7 @@ isc__socket_sendto2 isc__socket_sendtov isc__socket_sendv isc__socket_setname +isc__socket_socketevent isc__socketmgr_create isc__socketmgr_create2 isc__socketmgr_destroy @@ -387,6 +388,7 @@ isc_net_getudpportrange isc_net_ntop isc_net_probe_ipv6only isc_net_probe_ipv6pktinfo +isc_net_probedscp isc_net_probeipv4 isc_net_probeipv6 isc_net_probeunix @@ -517,6 +519,7 @@ isc_sockaddr_pf isc_sockaddr_setport isc_sockaddr_totext isc_sockaddr_v6fromin +isc_socket_dscp isc_socketmgr_renderxml isc_stats_attach isc_stats_create diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c index a41641e629..1526fbfde2 100644 --- a/lib/isc/win32/net.c +++ b/lib/isc/win32/net.c @@ -331,3 +331,8 @@ isc_net_enableipv6(void) { if (ipv6_result == ISC_R_DISABLED) ipv6_result = ISC_R_SUCCESS; } + +unsigned int +isc_net_probedscp() { + return (0); +} diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index f015974c59..2c2c3976f4 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -1061,13 +1061,13 @@ destroy_socketevent(isc_event_t *event) { } static isc_socketevent_t * -allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype, - isc_taskaction_t action, const void *arg) +allocate_socketevent(isc_mem_t *mctx, isc_socket_t *sock, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg) { isc_socketevent_t *ev; - ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, - sock, eventtype, + ev = (isc_socketevent_t *)isc_event_allocate(mctx, sock, eventtype, action, arg, sizeof(*ev)); if (ev == NULL) @@ -2840,7 +2840,8 @@ isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_RECVDONE, action, arg); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -2901,7 +2902,8 @@ isc__socket_recv(isc_socket_t *sock, isc_region_t *region, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_RECVDONE, action, arg); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -3064,7 +3066,8 @@ isc__socket_sendto(isc_socket_t *sock, isc_region_t *region, INSIST(sock->bound); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_SENDDONE, action, arg); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -3118,7 +3121,8 @@ isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, iocount = isc_bufferlist_usedcount(buflist); REQUIRE(iocount > 0); - dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + dev = allocate_socketevent(manager->mctx, sock, + ISC_SOCKEVENT_SENDDONE, action, arg); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -3803,6 +3807,34 @@ isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { #endif } +void +isc__socket_dscp(isc_socket_t *sock, unsigned int dscp) { +#if !defined(IP_TOS) && !defined(IPV6_TCLASS) + UNUSED(dscp); +#else + if (dscp < 0) + return; + + dscp <<= 2; + dscp &= 0xff; +#endif + + REQUIRE(VALID_SOCKET(sock)); + +#ifdef IP_TOS + if (sock->pf == AF_INET) { + (void)setsockopt(sock->fd, IPPROTO_IP, IP_TOS, + (char *)&dscp, sizeof(dscp)); + } +#endif +#ifdef IPV6_TCLASS + if (sock->pf == AF_INET6) { + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS, + (char *)&dscp, sizeof(dscp)); + } +#endif +} + void isc__socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active) { UNUSED(addr); @@ -3864,6 +3896,14 @@ isc___socketmgr_maxudp(isc_socketmgr_t *manager, int maxudp) { UNUSED(maxudp); } +isc_socketevent_t * +isc__socket_socketevent(isc_mem_t *mctx, void *sender, + isc_eventtype_t eventtype, isc_taskaction_t action, + const void *arg) +{ + return (allocate_socketevent(mctx, sender, eventtype, action, arg)); +} + #ifdef HAVE_LIBXML2 static const char * diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index b21a3d86ba..a68884b371 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -303,6 +303,20 @@ cfg_obj_assockaddr(const cfg_obj_t *obj); * if necessary. */ +isc_dscp_t +cfg_obj_getdscp(const cfg_obj_t *obj); +/*%< + * Returns the DSCP value of a configuration object representing a + * socket address. + * + * Requires: + * \li 'obj' points to a valid configuration object of a + * socket address type. + * + * Returns: + * \li DSCP value associated with a sockaddr, or -1. + */ + isc_boolean_t cfg_obj_isnetprefix(const cfg_obj_t *obj); /*%< diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index 2d7080c24c..a5d51bd1f4 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -157,6 +157,10 @@ struct cfg_obj { cfg_list_t list; cfg_obj_t ** tuple; isc_sockaddr_t sockaddr; + struct { + isc_sockaddr_t sockaddr; + isc_dscp_t dscp; + } sockaddrdscp; cfg_netprefix_t netprefix; } value; isc_refcount_t references; /*%< reference counter */ @@ -237,6 +241,7 @@ struct cfg_parser { #define CFG_ADDR_V4PREFIXOK 0x00000002 #define CFG_ADDR_V6OK 0x00000004 #define CFG_ADDR_WILDOK 0x00000008 +#define CFG_ADDR_DSCPOK 0x00000010 #define CFG_ADDR_MASK (CFG_ADDR_V6OK|CFG_ADDR_V4OK) /*@}*/ @@ -267,6 +272,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddrdscp; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4wild; @@ -325,6 +331,9 @@ cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags); isc_result_t cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port); +isc_result_t +cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp); + isc_result_t cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index fe47334ef5..8b194c154f 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -97,6 +97,7 @@ static cfg_type_t cfg_type_acl; static cfg_type_t cfg_type_addrmatchelt; static cfg_type_t cfg_type_bracketed_aml; static cfg_type_t cfg_type_bracketed_namesockaddrkeylist; +static cfg_type_t cfg_type_bracketed_dscpsockaddrlist; static cfg_type_t cfg_type_bracketed_sockaddrlist; static cfg_type_t cfg_type_bracketed_sockaddrnameportlist; static cfg_type_t cfg_type_controls; @@ -118,6 +119,7 @@ static cfg_type_t cfg_type_optional_class; static cfg_type_t cfg_type_optional_facility; static cfg_type_t cfg_type_optional_keyref; static cfg_type_t cfg_type_optional_port; +static cfg_type_t cfg_type_optional_dscp; static cfg_type_t cfg_type_options; static cfg_type_t cfg_type_portiplist; static cfg_type_t cfg_type_querysource4; @@ -181,11 +183,15 @@ static cfg_type_t cfg_type_tkey_dhkey = { static cfg_tuplefielddef_t listenon_fields[] = { { "port", &cfg_type_optional_port, 0 }, + { "dscp", &cfg_type_optional_dscp, 0 }, { "acl", &cfg_type_bracketed_aml, 0 }, { NULL, NULL, 0 } }; + static cfg_type_t cfg_type_listenon = { - "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields }; + "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, listenon_fields +}; /*% acl */ @@ -202,6 +208,7 @@ static cfg_type_t cfg_type_acl = { static cfg_tuplefielddef_t masters_fields[] = { { "name", &cfg_type_astring, 0 }, { "port", &cfg_type_optional_port, 0 }, + { "dscp", &cfg_type_optional_dscp, 0 }, { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, { NULL, NULL, 0 } }; @@ -234,6 +241,7 @@ static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = { static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = { { "port", &cfg_type_optional_port, 0 }, + { "dscp", &cfg_type_optional_dscp, 0 }, { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 }, { NULL, NULL, 0 } }; @@ -248,7 +256,8 @@ static cfg_type_t cfg_type_namesockaddrkeylist = { */ static cfg_tuplefielddef_t portiplist_fields[] = { { "port", &cfg_type_optional_port, 0 }, - { "addresses", &cfg_type_bracketed_sockaddrlist, 0 }, + { "dscp", &cfg_type_optional_dscp, 0 }, + { "addresses", &cfg_type_bracketed_dscpsockaddrlist, 0 }, { NULL, NULL, 0 } }; static cfg_type_t cfg_type_portiplist = { @@ -547,13 +556,20 @@ static cfg_tuplefielddef_t checknames_fields[] = { }; static cfg_type_t cfg_type_checknames = { - "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, - checknames_fields + "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, checknames_fields +}; + +static cfg_type_t cfg_type_bracketed_dscpsockaddrlist = { + "bracketed_sockaddrlist", cfg_parse_bracketed_list, + cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, + &cfg_type_sockaddrdscp }; static cfg_type_t cfg_type_bracketed_sockaddrlist = { - "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, - &cfg_rep_list, &cfg_type_sockaddr + "bracketed_sockaddrlist", cfg_parse_bracketed_list, + cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, + &cfg_type_sockaddr }; static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL }; @@ -592,8 +608,15 @@ static cfg_type_t cfg_type_zonestat = { }; static cfg_type_t cfg_type_rrsetorder = { - "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, - &cfg_rep_list, &cfg_type_rrsetorderingelement + "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_rrsetorderingelement +}; + +static keyword_type_t dscp_kw = { "dscp", &cfg_type_uint32 }; + +static cfg_type_t cfg_type_optional_dscp = { + "optional_dscp", parse_optional_keyvalue, print_keyvalue, + doc_optional_keyvalue, &cfg_rep_uint32, &dscp_kw }; static keyword_type_t port_kw = { "port", &cfg_type_uint32 }; @@ -934,6 +957,7 @@ options_clauses[] = { { "session-keyalg", &cfg_type_astring, 0 }, { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK }, + { "dscp", &cfg_type_uint32, 0 }, { "dump-file", &cfg_type_qstring, 0 }, { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "files", &cfg_type_size, 0 }, @@ -2033,7 +2057,9 @@ parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { } static isc_result_t -parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { +parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret)); } @@ -2379,9 +2405,11 @@ parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *obj = NULL; isc_netaddr_t netaddr; - in_port_t port; + in_port_t port = 0; + isc_dscp_t dscp = -1; unsigned int have_address = 0; unsigned int have_port = 0; + unsigned int have_dscp = 0; const unsigned int *flagp = type->of; if ((*flagp & CFG_ADDR_V4OK) != 0) @@ -2391,8 +2419,6 @@ parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { else INSIST(0); - port = 0; - for (;;) { CHECK(cfg_peektoken(pctx, 0)); if (pctx->token.type == isc_tokentype_string) { @@ -2412,11 +2438,20 @@ parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { CFG_ADDR_WILDOK, &port)); have_port++; - } else if (have_port == 0 && have_address == 0) { + } else if (strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) + { + /* read "dscp" */ + CHECK(cfg_gettoken(pctx, 0)); + CHECK(cfg_parse_dscp(pctx, &dscp)); + have_dscp++; + } else if (have_port == 0 && have_dscp == 0 && + have_address == 0) + { return (cfg_parse_sockaddr(pctx, type, ret)); } else { cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected 'address' or 'port'"); + "expected 'address', 'port', " + "or 'dscp'"); return (ISC_R_UNEXPECTEDTOKEN); } } else @@ -2428,8 +2463,14 @@ parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (ISC_R_UNEXPECTEDTOKEN); } + if (have_dscp > 1) { + cfg_parser_error(pctx, 0, "expected at most one dscp"); + return (ISC_R_UNEXPECTEDTOKEN); + } + CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj)); isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); + obj->value.sockaddrdscp.dscp = dscp; *ret = obj; return (ISC_R_SUCCESS); @@ -2447,10 +2488,16 @@ print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) { cfg_print_rawaddr(pctx, &na); cfg_print_cstr(pctx, " port "); cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr)); + if (obj->value.sockaddrdscp.dscp != -1) { + cfg_print_cstr(pctx, " dscp "); + cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); + } } -static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK; -static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK; +static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK | + CFG_ADDR_DSCPOK; +static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK | + CFG_ADDR_DSCPOK; static cfg_type_t cfg_type_querysource4 = { "querysource4", parse_querysource, NULL, cfg_doc_terminal, @@ -2780,7 +2827,7 @@ static cfg_type_t cfg_type_logfile = { &cfg_rep_tuple, logfile_fields }; -/*% An IPv4 address with optional port, "*" accepted as wildcard. */ +/*% An IPv4 address with optional dscp and port, "*" accepted as wildcard. */ static cfg_type_t cfg_type_sockaddr4wild = { "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags @@ -2923,8 +2970,10 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = { static cfg_tuplefielddef_t nameport_fields[] = { { "name", &cfg_type_astring, 0 }, { "port", &cfg_type_optional_port, 0 }, + { "dscp", &cfg_type_optional_dscp, 0 }, { NULL, NULL, 0 } }; + static cfg_type_t cfg_type_nameport = { "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, nameport_fields @@ -2937,14 +2986,20 @@ doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, ""); cfg_print_chars(pctx, " ", 1); cfg_print_cstr(pctx, "[ port ]"); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[ dscp ]"); cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, ""); cfg_print_chars(pctx, " ", 1); cfg_print_cstr(pctx, "[ port ]"); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[ dscp ]"); cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, ""); cfg_print_chars(pctx, " ", 1); cfg_print_cstr(pctx, "[ port ]"); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[ dscp ]"); cfg_print_chars(pctx, " )", 2); } @@ -2970,6 +3025,8 @@ parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type, &obj->value.tuple[0])); CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1])); + CHECK(cfg_parse_obj(pctx, fields[2].type, + &obj->value.tuple[2])); *ret = obj; obj = NULL; } diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index de0fa31ee2..52a65b33fd 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -1860,6 +1860,28 @@ cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); } +isc_result_t +cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) { + isc_result_t result; + + CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); + + if (pctx->token.type != isc_tokentype_number) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + if (pctx->token.value.as_ulong > 63) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "dscp out of range"); + return (ISC_R_RANGE); + } + *dscp = (isc_dscp_t)(pctx->token.value.as_ulong); + return (ISC_R_SUCCESS); + cleanup: + return (result); +} + /* netaddr */ static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; @@ -2030,17 +2052,43 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, isc_result_t result; isc_netaddr_t netaddr; in_port_t port = 0; + isc_dscp_t dscp = -1; cfg_obj_t *obj = NULL; + int have_port = 0, have_dscp = 0; CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - strcasecmp(TOKEN_STRING(pctx), "port") == 0) { - CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ - CHECK(cfg_parse_rawport(pctx, flags, &port)); + for (;;) { + CHECK(cfg_peektoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_string) { + if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) { + CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ + CHECK(cfg_parse_rawport(pctx, flags, &port)); + ++have_port; + } else if ((flags & CFG_ADDR_DSCPOK) != 0 && + strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) + { + CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */ + CHECK(cfg_parse_dscp(pctx, &dscp)); + ++have_dscp; + } else + break; + } else + break; + } + if (have_port > 1) { + cfg_parser_error(pctx, 0, "expected at most one port"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; + } + + if (have_dscp > 1) { + cfg_parser_error(pctx, 0, "expected at most one dscp"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; } isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); + obj->value.sockaddrdscp.dscp = dscp; *ret = obj; return (ISC_R_SUCCESS); @@ -2055,6 +2103,13 @@ cfg_type_t cfg_type_sockaddr = { &cfg_rep_sockaddr, &sockaddr_flags }; +static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK | + CFG_ADDR_DSCPOK; +cfg_type_t cfg_type_sockaddrdscp = { + "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, + &cfg_rep_sockaddr, &sockaddrdscp_flags +}; + isc_result_t cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { const unsigned int *flagp = type->of; @@ -2075,6 +2130,10 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { cfg_print_chars(pctx, " port ", 6); cfg_print_rawuint(pctx, port); } + if (obj->value.sockaddrdscp.dscp != -1) { + cfg_print_chars(pctx, " dscp ", 6); + cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); + } } void @@ -2105,6 +2164,9 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { } else { cfg_print_cstr(pctx, "[ port ]"); } + if ((*flagp & CFG_ADDR_DSCPOK) != 0) { + cfg_print_cstr(pctx, " [ dscp ]"); + } } isc_boolean_t @@ -2119,6 +2181,12 @@ cfg_obj_assockaddr(const cfg_obj_t *obj) { return (&obj->value.sockaddr); } +isc_dscp_t +cfg_obj_getdscp(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); + return (obj->value.sockaddrdscp.dscp); +} + isc_result_t cfg_gettoken(cfg_parser_t *pctx, int options) { isc_result_t result; diff --git a/lib/isccfg/win32/libisccfg.def b/lib/isccfg/win32/libisccfg.def index 98abbcf8e2..e5d5bd873a 100644 --- a/lib/isccfg/win32/libisccfg.def +++ b/lib/isccfg/win32/libisccfg.def @@ -22,6 +22,7 @@ cfg_obj_asuint64 cfg_obj_attach cfg_obj_destroy cfg_obj_file +cfg_obj_getdscp cfg_obj_isboolean cfg_obj_islist cfg_obj_ismap -- GitLab