diff --git a/CHANGES b/CHANGES index e0abd96218..474c31a4c4 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,18 @@ 1438. [func] Log TSIG (if any) when logging NOTIFY requests. +1442. [func] New fuctions for manipulating port lists: + dns_portlist_create(), dns_portlist_add(), + dns_portlist_remove(), dns_portlist_match(), + dns_portlist_attach() and dns_portlist_detach(). + +1441. [func] It is now possible to tell dig to bind to a specific + source port. + +1440. [func] It is now possible to tell named to avoid using + certian source ports (avoid-v4-udp-ports, + avoid-v6-udp-ports). + 1436. [func] dns_zonemgr_resumexfrs() can be used to restart stalled transfers. diff --git a/bin/dig/dig.c b/bin/dig/dig.c index ee714b7cd6..aa8d0b2ec0 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.c,v 1.157.2.13.2.8 2003/08/15 02:00:32 marka Exp $ */ +/* $Id: dig.c,v 1.157.2.13.2.9 2003/08/27 01:39:22 marka Exp $ */ #include #include @@ -994,6 +994,8 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, char textname[MXNAME]; struct in_addr in4; struct in6_addr in6; + in_port_t srcport; + char *hash; cmd = option[0]; if (strlen(option) > 1U) { @@ -1029,12 +1031,24 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, goto invalid_option; switch (cmd) { case 'b': + hash = index(value, '#'); + if (hash != NULL) { + srcport = (in_port_t) parse_uint(hash + 1, + "port number", MAXPORT); + *hash = '\0'; + } else + srcport = 0; if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) - isc_sockaddr_fromin6(&bind_address, &in6, 0); + isc_sockaddr_fromin6(&bind_address, &in6, srcport); else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) - isc_sockaddr_fromin(&bind_address, &in4, 0); - else + isc_sockaddr_fromin(&bind_address, &in4, srcport); + else { + if (hash != NULL) + *hash = '#'; fatal("invalid address %s", value); + } + if (hash != NULL) + *hash = '#'; specified_source = ISC_TRUE; return (value_from_next); case 'c': diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index 92f6bb3ae1..26239ea7a3 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -16,7 +16,7 @@ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --> - + @@ -153,7 +153,8 @@ ANY, A, MX, SIG, etc. The option sets the source IP address of the query to address. This must be a valid address on -one of the host's network interfaces. +one of the host's network interfaces or "0.0.0.0" or "::". An optional port +may be specified by appending "#<port>" diff --git a/bin/named/server.c b/bin/named/server.c index e81480fd15..16ad19daf2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.339.2.15.2.29 2003/08/26 07:54:18 marka Exp $ */ +/* $Id: server.c,v 1.339.2.15.2.30 2003/08/27 01:39:23 marka Exp $ */ #include @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1790,6 +1791,26 @@ set_limits(cfg_obj_t **maps) { SETLIMIT("files", openfiles, "open files"); } +static isc_result_t +portlist_fromconf(dns_portlist_t *portlist, unsigned int family, + cfg_obj_t *ports) +{ + cfg_listelt_t *element; + isc_result_t result = ISC_R_SUCCESS; + + for (element = cfg_list_first(ports); + element != NULL; + element = cfg_list_next(element)) { + cfg_obj_t *obj = cfg_listelt_value(element); + in_port_t port = cfg_obj_asuint32(obj); + + result = dns_portlist_add(portlist, family, port); + if (result != ISC_R_SUCCESS) + break; + } + return (result); +} + static isc_result_t load_configuration(const char *filename, ns_server_t *server, isc_boolean_t first_time) @@ -1800,6 +1821,7 @@ load_configuration(const char *filename, ns_server_t *server, cfg_obj_t *options; cfg_obj_t *views; cfg_obj_t *obj; + cfg_obj_t *v4ports, *v6ports; cfg_obj_t *maps[3]; cfg_obj_t *builtin_views; cfg_listelt_t *element; @@ -1913,6 +1935,25 @@ load_configuration(const char *filename, ns_server_t *server, INSIST(result == ISC_R_SUCCESS); server->aclenv.match_mapped = cfg_obj_asboolean(obj); + v4ports = NULL; + v6ports = NULL; + (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports); + (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports); + if (v4ports != NULL || v6ports != NULL) { + dns_portlist_t *portlist = NULL; + result = dns_portlist_create(ns_g_mctx, &portlist); + if (result == ISC_R_SUCCESS && v4ports != NULL) + result = portlist_fromconf(portlist, AF_INET, v4ports); + if (result == ISC_R_SUCCESS && v6ports != NULL) + portlist_fromconf(portlist, AF_INET6, v6ports); + if (result == ISC_R_SUCCESS) + dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist); + if (portlist != NULL) + dns_portlist_detach(&portlist); + CHECK(result); + } else + dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL); + /* * Set the EDNS UDP size when we don't match a view. */ diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index a11aee917f..b97d4b0a34 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -2,7 +2,7 @@ - + BIND 9 Administrator Reference Manual @@ -2693,6 +2693,8 @@ statement in the named.conf file: allow-recursion { address_match_list }; allow-v6-synthesis { address_match_list }; blackhole { address_match_list }; + avoid-v4-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 }; query-source address ( ip_addr | * ) port ( ip_port | * ) ; @@ -3368,6 +3370,7 @@ and on port 1234 of IPv6 addresses that is not in the prefix If no listen-on-v6 statement is specified, the server will not listen on any IPv6 address. + Query Address If the server doesn't know the answer to a question, it will query other nameservers. query-source specifies @@ -3376,7 +3379,9 @@ IPv6, there is a separate query-source-v6 option. If address is * or is omitted, a wildcard IP address (INADDR_ANY) will be used. If port is * or is omitted, -a random unprivileged port will be used. The defaults are +a random unprivileged port will be used, avoid-v4-udp-ports +and avoid-v6-udp-ports can be used to prevent named +from selecting certian ports. The defaults are query-source address * port *; query-source-v6 address * port *; @@ -3384,7 +3389,8 @@ query-source-v6 address * port *; The address specified in the query-source option is used for both UDP and TCP queries, but the port applies only to UDP queries. TCP queries always use a random -unprivileged port. +unprivileged port. + Zone Transfers BIND has mechanisms in place to facilitate zone transfers @@ -3598,6 +3604,18 @@ may use. The default is default. + +Bad UDP Port Lists + +avoid-v4-udp-ports and avoid-v6-udp-ports +specify a list of IPv4 and IPv6 UDP ports that will not be used as system +assigned source ports for UDP sockets. These lists are expected to be +used to prevent named using "well known" ports in the system assigned range +that have become unusable due to wide spread use of acls containing these +ports. + + + Server Resource Limits diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index 6fbb84a395..6768bb738d 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.126.2.3.2.3 2003/08/25 04:16:22 marka Exp $ +# $Id: Makefile.in,v 1.126.2.3.2.4 2003/08/27 01:39:25 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -49,7 +49,7 @@ OBJS = acl.@O@ adb.@O@ byaddr.@O@ \ dnssec.@O@ forward.@O@ journal.@O@ keytable.@O@ \ lib.@O@ log.@O@ lookup.@O@ \ master.@O@ masterdump.@O@ message.@O@ \ - name.@O@ ncache.@O@ nxt.@O@ order.@O@ peer.@O@ \ + name.@O@ ncache.@O@ nxt.@O@ order.@O@ peer.@O@ portlist.@O@ \ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rdata.@O@ rdatalist.@O@ \ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \ resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ soa.@O@ ssu.@O@ \ @@ -65,7 +65,7 @@ SRCS = acl.c adb.c byaddr.c \ dnssec.c forward.c journal.c keytable.c \ lib.c log.c lookup.c \ master.c masterdump.c message.c \ - name.c ncache.c nxt.c order.c peer.c \ + name.c ncache.c nxt.c order.c peer.c portlist.c \ rbt.c rbtdb.c rbtdb64.c rdata.c rdatalist.c \ rdataset.c rdatasetiter.c rdataslab.c request.c \ resolver.c result.c rootns.c sdb.c soa.c ssu.c \ diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 3b1013b88d..1af8d58790 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.101.2.6.2.2 2003/08/19 02:53:57 marka Exp $ */ +/* $Id: dispatch.c,v 1.101.2.6.2.3 2003/08/27 01:39:25 marka Exp $ */ #include @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ struct dns_dispatchmgr { unsigned int magic; isc_mem_t *mctx; dns_acl_t *blackhole; + dns_portlist_t *portlist; /* Locked by "lock". */ isc_mutex_t lock; @@ -986,6 +988,9 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { if (mgr->blackhole != NULL) dns_acl_detach(&mgr->blackhole); + if (mgr->portlist != NULL) + dns_portlist_detach(&mgr->portlist); + isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t)); isc_mem_detach(&mctx); } @@ -1038,6 +1043,7 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_mem_attach(mctx, &mgr->mctx); mgr->blackhole = NULL; + mgr->portlist = NULL; result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) @@ -1131,6 +1137,23 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { return (mgr->blackhole); } +void +dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr, + dns_portlist_t *portlist) +{ + REQUIRE(VALID_DISPATCHMGR(mgr)); + if (mgr->portlist != NULL) + dns_portlist_detach(&mgr->portlist); + if (portlist != NULL) + dns_portlist_attach(portlist, &mgr->portlist); +} + +dns_portlist_t * +dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + return (mgr->portlist); +} + static isc_result_t dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, unsigned int maxbuffers, @@ -1215,16 +1238,63 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { destroy_mgr(&mgr); } +static isc_boolean_t +blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock) { + isc_sockaddr_t sockaddr; + isc_result_t result; + + if (mgr->portlist == NULL) + return (ISC_FALSE); + + result = isc_socket_getsockname(sock, &sockaddr); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + + if (mgr->portlist != NULL && + dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr), + isc_sockaddr_getport(&sockaddr))) + return (ISC_TRUE); + return (ISC_FALSE); +} #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask))) static isc_boolean_t local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) { + isc_sockaddr_t sockaddr; + isc_result_t result; if (addr == NULL) return (ISC_TRUE); - return (isc_sockaddr_equal(&disp->local, addr)); + /* + * Don't match wildcard ports against newly blacklisted ports. + */ + if (disp->mgr->portlist != NULL && + isc_sockaddr_getport(addr) == 0 && + isc_sockaddr_getport(&disp->local) == 0 && + blacklisted(disp->mgr, disp->socket)) + return (ISC_FALSE); + + /* + * Check if we match the binding . + * Wildcard ports match/fail here. + */ + if (isc_sockaddr_equal(&disp->local, addr)) + return (ISC_TRUE); + if (isc_sockaddr_getport(addr) == 0) + return (ISC_FALSE); + + /* + * Check if we match a bound wildcard port . + */ + if (!isc_sockaddr_eqaddr(&disp->local, addr)) + return (ISC_FALSE); + result = isc_socket_getsockname(disp->socket, &sockaddr); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + + return (isc_sockaddr_equal(&disp->local, &sockaddr)); } /* @@ -1635,9 +1705,20 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, if (result != ISC_R_SUCCESS) return (result); + /* + * This assumes that the IP stack will *not* quickly reallocate + * the same port. If it does continually reallocate the same port + * then we need a mechanism to hold all the blacklisted sockets + * until we find a usable socket. + */ + getsocket: result = create_socket(sockmgr, localaddr, &sock); if (result != ISC_R_SUCCESS) goto deallocate_dispatch; + if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) { + isc_socket_detach(&sock); + goto getsocket; + } disp->socktype = isc_sockettype_udp; disp->socket = sock; diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in index b22a3f4192..a1033e90f9 100644 --- a/lib/dns/include/dns/Makefile.in +++ b/lib/dns/include/dns/Makefile.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.43.2.1.10.1 2003/08/25 04:16:25 marka Exp $ +# $Id: Makefile.in,v 1.43.2.1.10.2 2003/08/27 01:39:25 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -27,7 +27,7 @@ HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \ dnssec.h events.h fixedname.h journal.h keyflags.h \ keytable.h keyvalues.h lib.h log.h master.h masterdump.h \ message.h name.h ncache.h \ - nxt.h peer.h rbt.h rcode.h \ + nxt.h peer.h portlist.h rbt.h rcode.h \ rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ rdataslab.h rdatatype.h request.h resolver.h result.h \ rootns.h sdb.h secalg.h secproto.h soa.h ssu.h \ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index ecbcd55d7b..349d53c407 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.h,v 1.45.2.2 2003/03/06 04:38:22 marka Exp $ */ +/* $Id: dispatch.h,v 1.45.2.2.4.1 2003/08/27 01:39:25 marka Exp $ */ #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 @@ -179,6 +179,28 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr); * A pointer to the current blackhole list, or NULL. */ +void +dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr, + dns_portlist_t *portlist); +/* + * Sets a list of UDP ports that won't be used when creating a udp + * dispatch with a wildcard port. + * + * Requires: + * mgr is a valid dispatchmgr + * portlist to be NULL or a valid port list. + */ + +dns_portlist_t * +dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr); +/* + * Return the current port list. + * + * Requires: + * mgr is a valid dispatchmgr + */ + + isc_result_t dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index eb8fed6921..467695c538 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.103.12.4 2003/08/25 04:16:25 marka Exp $ */ +/* $Id: types.h,v 1.103.12.5 2003/08/27 01:39:25 marka Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -78,6 +78,7 @@ typedef unsigned char dns_offsets_t[128]; typedef struct dns_order dns_order_t; typedef struct dns_peer dns_peer_t; typedef struct dns_peerlist dns_peerlist_t; +typedef struct dns_portlist dns_portlist_t; typedef struct dns_rbt dns_rbt_t; typedef isc_uint16_t dns_rcode_t; typedef struct dns_rdata dns_rdata_t; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 7e56d01614..0432c3ddff 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.21.44.12 2003/08/26 05:56:18 marka Exp $ */ +/* $Id: namedconf.c,v 1.21.44.13 2003/08/27 01:39:26 marka Exp $ */ #include @@ -488,6 +488,35 @@ doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) { static cfg_type_t cfg_type_serverid = { "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL }; +/* + * Port list. + */ +static isc_result_t +parse_port(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + isc_result_t result; + + UNUSED(type); + + CHECK(cfg_parse_uint32(pctx, NULL, ret)); + if ((*ret)->value.uint32 > 0xffff) { + cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port"); + cfg_obj_destroy(pctx, ret); + result = ISC_R_RANGE; + } + cleanup: + return (result); +} + +static cfg_type_t cfg_type_port = { + "port", parse_port, NULL, cfg_doc_terminal, + NULL, NULL +}; + +static cfg_type_t cfg_type_bracketed_portlist = { + "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, + &cfg_rep_list, &cfg_type_port +}; + /* * Clauses that can be found within the top level of the named.conf * file only. @@ -526,6 +555,8 @@ namedconf_or_view_clauses[] = { */ static cfg_clausedef_t options_clauses[] = { + { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, + { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, { "blackhole", &cfg_type_bracketed_aml, 0 }, { "coresize", &cfg_type_size, 0 }, { "datasize", &cfg_type_size, 0 }, diff --git a/util/copyrights b/util/copyrights index 2aafd0c020..143fd21856 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1556,6 +1556,7 @@ ./lib/dns/include/dns/nxt.h C 1999,2000,2001 ./lib/dns/include/dns/order.h C 2002 ./lib/dns/include/dns/peer.h C 2000,2001 +./lib/dns/include/dns/portlist.h C 2003 ./lib/dns/include/dns/rbt.h C 1999,2000,2001 ./lib/dns/include/dns/rcode.h C 1999,2000,2001 ./lib/dns/include/dns/rdata.h C 1998,1999,2000,2001,2002 @@ -1601,6 +1602,7 @@ ./lib/dns/nxt.c C 1999,2000,2001 ./lib/dns/order.c C 2002 ./lib/dns/peer.c C 2000,2001 +./lib/dns/portlist.c C 2003 ./lib/dns/rbt.c C 1999,2000,2001,2003 ./lib/dns/rbtdb.c C 1999,2000,2001,2002,2003 ./lib/dns/rbtdb.h C 1999,2000,2001