From b312748a11d27fe387984973ba79975a9d6863c4 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 26 Feb 2003 05:05:16 +0000 Subject: [PATCH] 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). developer: marka reviewer: explorer --- CHANGES | 12 ++ bin/dig/dig.c | 22 ++- bin/dig/dig.docbook | 5 +- bin/named/server.c | 43 +++++- doc/arm/Bv9ARM-book.xml | 24 ++- lib/dns/Makefile.in | 6 +- lib/dns/dispatch.c | 85 ++++++++++- lib/dns/include/dns/Makefile.in | 4 +- lib/dns/include/dns/dispatch.h | 24 ++- lib/dns/include/dns/portlist.h | 99 ++++++++++++ lib/dns/include/dns/types.h | 3 +- lib/dns/portlist.c | 258 ++++++++++++++++++++++++++++++++ lib/isccfg/namedconf.c | 33 +++- util/copyrights | 2 + 14 files changed, 600 insertions(+), 20 deletions(-) create mode 100644 lib/dns/include/dns/portlist.h create mode 100644 lib/dns/portlist.c diff --git a/CHANGES b/CHANGES index 8fc0bbccf9..d6c092e097 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +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). + 1439. [bug] Named could return NOERROR with certian NOTIFY failures. Return NOTAUTH is the NOTIFY zone is not being served. diff --git a/bin/dig/dig.c b/bin/dig/dig.c index 5b5d5d48d2..d988a0a605 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.180 2002/08/29 07:45:04 marka Exp $ */ +/* $Id: dig.c,v 1.181 2003/02/26 05:05:13 marka Exp $ */ #include #include @@ -996,6 +996,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) > 1) { @@ -1031,12 +1033,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 0c529d1d2f..2565aa8f52 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 f293ddcd18..9a2e17eb9d 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.396 2003/02/26 03:45:58 marka Exp $ */ +/* $Id: server.c,v 1.397 2003/02/26 05:05:14 marka Exp $ */ #include @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1748,6 +1749,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) @@ -1758,6 +1779,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; @@ -1871,6 +1893,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 ca396c8165..c520e1032f 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -2,7 +2,7 @@ - + BIND 9 Administrator Reference Manual @@ -2727,6 +2727,8 @@ statement in the named.conf file: allow-update-forwarding { 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 | * ) ; @@ -3447,6 +3449,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 name servers. query-source specifies @@ -3455,7 +3458,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 *; @@ -3463,7 +3468,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 @@ -3619,6 +3625,18 @@ but applies to notify messages sent to IPv6 addresses. + +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. + + + Operating System Resource Limits diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index ad91dde5e9..54a6ccff18 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.136 2002/12/13 02:51:40 marka Exp $ +# $Id: Makefile.in,v 1.137 2003/02/26 05:05:15 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -49,7 +49,7 @@ OBJS = acl.@O@ adb.@O@ byaddr.@O@ \ dnssec.@O@ ds.@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 ds.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 2638abcf4d..810c3970c5 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.111 2002/12/05 03:55:09 marka Exp $ */ +/* $Id: dispatch.c,v 1.112 2003/02/26 05:05:15 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 26119fde6d..8a0bfe5424 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.47 2002/11/27 09:52:56 marka Exp $ +# $Id: Makefile.in,v 1.48 2003/02/26 05:05:15 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -27,7 +27,7 @@ HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \ dnssec.h ds.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 a3ed03968c..b153c3ce86 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.46 2002/09/04 02:26:13 jinmei Exp $ */ +/* $Id: dispatch.h,v 1.47 2003/02/26 05:05:15 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/portlist.h b/lib/dns/include/dns/portlist.h new file mode 100644 index 0000000000..5601937feb --- /dev/null +++ b/lib/dns/include/dns/portlist.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM 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. + */ + +/* $Id: portlist.h,v 1.2 2003/02/26 05:05:15 marka Exp $ */ + +#include +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp); +/* + * Create a port list. + * + * Requires: + * 'mctx' to be valid. + * 'portlistp' to be non NULL and '*portlistp' to be NULL; + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * ISC_R_UNEXPECTED + */ + +isc_result_t +dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port); +/* + * Add the given tuple to the portlist. + * + * Requires: + * 'portlist' to be valid. + * 'af' to be AF_INET or AF_INET6 + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +void +dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port); +/* + * Remove the given tuple to the portlist. + * + * Requires: + * 'portlist' to be valid. + * 'af' to be AF_INET or AF_INET6 + */ + +isc_boolean_t +dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port); +/* + * Find the given tuple to the portlist. + * + * Requires: + * 'portlist' to be valid. + * 'af' to be AF_INET or AF_INET6 + * + * Returns + * ISC_TRUE if the tuple is found, ISC_FALSE otherwise. + */ + +void +dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp); +/* + * Attach to a port list. + * + * Requires: + * 'portlist' to be valid. + * 'portlistp' to be non NULL and '*portlistp' to be NULL; + */ + +void +dns_portlist_detach(dns_portlist_t **portlistp); +/* + * Detach from a port list. + * + * Requires: + * '*portlistp' to be valid. + */ + +ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index b3b4327e51..05dac6888f 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.107 2002/11/27 09:52:56 marka Exp $ */ +/* $Id: types.h,v 1.108 2003/02/26 05:05:15 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/dns/portlist.c b/lib/dns/portlist.c new file mode 100644 index 0000000000..36b85fb09a --- /dev/null +++ b/lib/dns/portlist.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM 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. + */ + +/* $Id: portlist.c,v 1.2 2003/02/26 05:05:15 marka Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T') +#define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC) + +typedef struct dns_element { + in_port_t port; + isc_uint16_t flags; +} dns_element_t; + +struct dns_portlist { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t refcount; + isc_mutex_t lock; + dns_element_t *list; + unsigned int allocated; + unsigned int active; +}; + +#define DNS_PL_INET 0x0001 +#define DNS_PL_INET6 0x0002 +#define DNS_PL_ALLOCATE 16 + +static int +compare(const void *arg1, const void *arg2) { + const dns_element_t *e1 = (const dns_element_t *)arg1; + const dns_element_t *e2 = (const dns_element_t *)arg2; + + if (e1->port < e2->port) + return (-1); + if (e1->port > e2->port) + return (1); + return (0); +} + +isc_result_t +dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) { + dns_portlist_t *portlist; + isc_result_t result; + + REQUIRE(portlistp != NULL && *portlistp == NULL); + + portlist = isc_mem_get(mctx, sizeof(*portlist)); + if (portlist == NULL) + return (ISC_R_NOMEMORY); + result = isc_mutex_init(&portlist->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, portlist, sizeof(*portlist)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_mutex_init() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + isc_refcount_init(&portlist->refcount, 1); + portlist->list = NULL; + portlist->allocated = 0; + portlist->active = 0; + portlist->mctx = NULL; + isc_mem_attach(mctx, &portlist->mctx); + portlist->magic = DNS_PORTLIST_MAGIC; + *portlistp = portlist; + return (ISC_R_SUCCESS); +} + +static dns_element_t * +find_port(dns_element_t *list, unsigned int len, in_port_t port) { + unsigned int try = len / 2; + unsigned int min = 0; + unsigned int max = len - 1; + unsigned int last = len; + + while (1) { + if (list[try].port == port) + return (&list[try]); + if (port > list[try].port) { + if (try == max) + return (NULL); + min = try; + try = try + (max - try + 1) / 2; + INSIST(try <= max); + if (try == last) + return (NULL); + last = min; + } else { + if (try == min) + return (NULL); + max = try; + try = try - (try - min + 1) / 2; + INSIST(try >= min); + if (try == last) + return (NULL); + last = max; + } + } +} + +isc_result_t +dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) { + dns_element_t *el; + isc_result_t result; + + REQUIRE(DNS_VALID_PORTLIST(portlist)); + REQUIRE(af == AF_INET || af == AF_INET6); + + LOCK(&portlist->lock); + if (portlist->active != 0) { + el = find_port(portlist->list, portlist->active, port); + if (el != NULL) { + if (af == AF_INET) + el->flags |= DNS_PL_INET; + else + el->flags |= DNS_PL_INET6; + result = ISC_R_SUCCESS; + goto unlock; + } + } + + if (portlist->allocated <= portlist->active) { + unsigned int allocated; + allocated = portlist->allocated + DNS_PL_ALLOCATE; + el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated); + if (el == NULL) { + result = ISC_R_NOMEMORY; + goto unlock; + } + if (portlist->list != NULL) { + memcpy(el, portlist->list, + portlist->allocated * sizeof(*el)); + isc_mem_put(portlist->mctx, portlist->list, + portlist->allocated * sizeof(*el)); + } + portlist->list = el; + portlist->allocated = allocated; + } + portlist->list[portlist->active].port = port; + if (af == AF_INET) + portlist->list[portlist->active].flags = DNS_PL_INET; + else + portlist->list[portlist->active].flags = DNS_PL_INET6; + portlist->active++; + qsort(portlist->list, portlist->active, sizeof(*el), compare); + result = ISC_R_SUCCESS; + unlock: + UNLOCK(&portlist->lock); + return (result); +} + +void +dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) { + dns_element_t *el; + + REQUIRE(DNS_VALID_PORTLIST(portlist)); + REQUIRE(af == AF_INET || af == AF_INET6); + + LOCK(&portlist->lock); + if (portlist->active != 0) { + el = find_port(portlist->list, portlist->active, port); + if (el != NULL) { + if (af == AF_INET) + el->flags &= ~DNS_PL_INET; + else + el->flags &= ~DNS_PL_INET6; + if (el->flags == 0) { + *el = portlist->list[portlist->active]; + portlist->active--; + qsort(portlist->list, portlist->active, + sizeof(*el), compare); + } + } + } + UNLOCK(&portlist->lock); +} + +isc_boolean_t +dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) { + dns_element_t *el; + isc_boolean_t result = ISC_FALSE; + + REQUIRE(DNS_VALID_PORTLIST(portlist)); + REQUIRE(af == AF_INET || af == AF_INET6); + LOCK(&portlist->lock); + if (portlist->active != 0) { + el = find_port(portlist->list, portlist->active, port); + if (el != NULL) { + if (af == AF_INET && (el->flags & DNS_PL_INET) != 0) + result = ISC_TRUE; + if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0) + result = ISC_TRUE; + } + } + UNLOCK(&portlist->lock); + return (result); +} + +void +dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) { + + REQUIRE(DNS_VALID_PORTLIST(portlist)); + REQUIRE(portlistp != NULL && *portlistp == NULL); + + isc_refcount_increment(&portlist->refcount, NULL); + *portlistp = portlist; +} + +void +dns_portlist_detach(dns_portlist_t **portlistp) { + dns_portlist_t *portlist; + unsigned int count; + + REQUIRE(portlistp != NULL); + portlist = *portlistp; + REQUIRE(DNS_VALID_PORTLIST(portlist)); + *portlistp = NULL; + isc_refcount_decrement(&portlist->refcount, &count); + if (count == 0) { + portlist->magic = 0; + isc_refcount_destroy(&portlist->refcount); + if (portlist->list != NULL) + isc_mem_put(portlist->mctx, portlist->list, + portlist->allocated * + sizeof(*portlist->list)); + DESTROYLOCK(&portlist->lock); + isc_mem_putanddetach(&portlist->mctx, portlist, + sizeof(*portlist)); + } +} diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 2e8b02a2d3..e224aa4aec 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.16 2003/02/26 02:04:00 marka Exp $ */ +/* $Id: namedconf.c,v 1.17 2003/02/26 05:05:16 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. @@ -521,6 +550,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 5644e7a3b3..6d8bb669c4 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1649,6 +1649,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 @@ -1695,6 +1696,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 ./lib/dns/rbtdb.c C 1999,2000,2001 ./lib/dns/rbtdb.h C 1999,2000,2001