diff --git a/CHANGES b/CHANGES index 2d07ffd407..792a9d40e2 100644 --- a/CHANGES +++ b/CHANGES @@ -25,7 +25,7 @@ 1681. [bug] Only set SO_REUSEADDR when a port is specified in isc_socket_bind(). [RT #11742] -1680. [placeholder] rt11697 +1680. [func] rndc: the source address can now be specified. 1679. [bug] When there was a single nameserver with multiple addresses for a zone not all addresses were tried. diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c index 37bfd8d33c..38f24efa8f 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rndc.c,v 1.97 2004/06/18 04:38:46 marka Exp $ */ +/* $Id: rndc.c,v 1.98 2004/07/23 04:15:23 marka Exp $ */ /* * Principal Author: DCL @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,8 @@ static const char *admin_keyfile; static const char *version = VERSION; static const char *servername = NULL; static isc_sockaddr_t serveraddrs[SERVERADDRS]; +static isc_sockaddr_t local4, local6; +static isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE; static int nserveraddrs; static int currentaddr = 0; static unsigned int remoteport = 0; @@ -169,10 +172,12 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) { if (ccmsg.result == ISC_R_EOF) fatal("connection to remote host closed\n" - "This may indicate that the remote server is using " - "an older version of \n" - "the command protocol, this host is not authorized " - "to connect,\nor the key is invalid."); + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not syncronized, or\n" + "* the key is invalid."); if (ccmsg.result != ISC_R_SUCCESS) fatal("recv failed: %s", isc_result_totext(ccmsg.result)); @@ -228,10 +233,12 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) { if (ccmsg.result == ISC_R_EOF) fatal("connection to remote host closed\n" - "This may indicate that the remote server is using " - "an older version of \n" - "the command protocol, this host is not authorized " - "to connect,\nor the key is invalid."); + "This may indicate that\n" + "* the remote server is using an older version of" + " the command protocol,\n" + "* this host is not authorized to connect,\n" + "* the clocks are not syncronized, or\n" + "* the key is invalid."); if (ccmsg.result != ISC_R_SUCCESS) fatal("recv failed: %s", isc_result_totext(ccmsg.result)); @@ -357,6 +364,16 @@ rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) { DO("create socket", isc_socket_create(socketmgr, isc_sockaddr_pf(addr), isc_sockettype_tcp, &sock)); + switch (isc_sockaddr_pf(addr)) { + case AF_INET: + DO("bind socket", isc_socket_bind(sock, &local4)); + break; + case AF_INET6: + DO("bind socket", isc_socket_bind(sock, &local6)); + break; + default: + break; + } DO("connect", isc_socket_connect(sock, addr, task, rndc_connected, NULL)); connects++; @@ -387,6 +404,7 @@ parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, cfg_obj_t *secretobj = NULL; cfg_obj_t *algorithmobj = NULL; cfg_obj_t *config = NULL; + cfg_obj_t *address = NULL; cfg_listelt_t *elt; const char *secretstr; const char *algorithm; @@ -524,10 +542,9 @@ parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, element != NULL; element = cfg_list_next(element)) { - - cfg_obj_t *address = cfg_listelt_value(element); isc_sockaddr_t sa; + address = cfg_listelt_value(element); if (!cfg_obj_issockaddr(address)) { unsigned int myport; const char *name; @@ -567,6 +584,41 @@ parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, } } } + + if (!local4set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = ISC_TRUE; + } + } + if (!local4set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address", &address); + if (address != NULL) { + local4 = *cfg_obj_assockaddr(address); + local4set = ISC_TRUE; + } + } + + if (!local6set && server != NULL) { + address = NULL; + cfg_map_get(server, "source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = ISC_TRUE; + } + } + if (!local6set && options != NULL) { + address = NULL; + cfg_map_get(options, "default-source-address-v6", &address); + if (address != NULL) { + local6 = *cfg_obj_assockaddr(address); + local6set = ISC_TRUE; + } + } + *configp = config; } @@ -582,6 +634,8 @@ main(int argc, char **argv) { cfg_parser_t *pctx = NULL; cfg_obj_t *config = NULL; const char *keyname = NULL; + struct in_addr in; + struct in6_addr in6; char *p; size_t argslen; int ch; @@ -595,13 +649,28 @@ main(int argc, char **argv) { admin_conffile = RNDC_CONFFILE; admin_keyfile = RNDC_KEYFILE; + isc_sockaddr_any(&local4); + isc_sockaddr_any6(&local6); + result = isc_app_start(); if (result != ISC_R_SUCCESS) fatal("isc_app_start() failed: %s", isc_result_totext(result)); - while ((ch = isc_commandline_parse(argc, argv, "c:k:Mmp:s:Vy:")) + while ((ch = isc_commandline_parse(argc, argv, "b:c:k:Mmp:s:Vy:")) != -1) { switch (ch) { + case 'b': + if (inet_pton(AF_INET, isc_commandline_argument, + &in) == 1) { + isc_sockaddr_fromin(&local4, &in, 0); + local4set = ISC_TRUE; + } else if (inet_pton(AF_INET6, isc_commandline_argument, + &in6) == 1) { + isc_sockaddr_fromin6(&local6, &in6, 0); + local6set = ISC_TRUE; + } + break; + case 'c': admin_conffile = isc_commandline_argument; break; @@ -628,15 +697,19 @@ main(int argc, char **argv) { case 's': servername = isc_commandline_argument; break; + case 'V': verbose = ISC_TRUE; break; + case 'y': keyname = isc_commandline_argument; break; + case '?': usage(0); break; + default: fatal("unexpected error parsing command arguments: " "got %c\n", ch); diff --git a/bin/rndc/rndc.conf.docbook b/bin/rndc/rndc.conf.docbook index 58a910ee22..1d486eae12 100644 --- a/bin/rndc/rndc.conf.docbook +++ b/bin/rndc/rndc.conf.docbook @@ -16,7 +16,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -67,7 +67,7 @@ and a key statement. - The statement contains three clauses. + The statement contains five clauses. The clause is followed by the name or address of a name server. This host will be used when no name server is given as an argument to @@ -84,6 +84,10 @@ line, and no clause is found in a matching statement, this default port will be used to connect. + The and + clauses which + can be used to set the IPv4 and IPv6 source addresses + respectively. After the keyword, the server @@ -95,6 +99,9 @@ specifies the port to connect to. If an clause is supplied these addresses will be used instead of the server name. Each address can take a optional port. + If an or + of supplied then these will be used to specify the IPv4 and IPv6 + source addresses respectively. The statement begins with an identifying diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook index 6ddb40b2c3..f54e59781c 100644 --- a/bin/rndc/rndc.docbook +++ b/bin/rndc/rndc.docbook @@ -16,7 +16,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -37,6 +37,7 @@ rndc + @@ -81,6 +82,18 @@ OPTIONS + + -b source-address + + + Use source-address + as the source address for the connection to the server. + Multiple instances are permitted to allow setting of both + the IPv4 and IPv6 source addresses. + + + + -c config-file diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index 5431e7e093..74b2bb5528 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: grammar.h,v 1.4 2004/03/05 05:12:27 marka Exp $ */ +/* $Id: grammar.h,v 1.5 2004/07/23 04:15:27 marka Exp $ */ #ifndef ISCCFG_GRAMMAR_H #define ISCCFG_GRAMMAR_H 1 @@ -248,6 +248,10 @@ 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_netaddr; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4wild; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr6wild; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netprefix; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_void; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 9059656f7b..391118d494 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.35 2004/06/18 04:38:45 marka Exp $ */ +/* $Id: namedconf.c,v 1.36 2004/07/23 04:15:26 marka Exp $ */ #include @@ -1680,7 +1680,9 @@ lwres_clausesets[] = { NULL }; static cfg_type_t cfg_type_lwres = { - "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, lwres_clausesets }; + "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, + lwres_clausesets +}; /* * rndc @@ -1688,9 +1690,11 @@ static cfg_type_t cfg_type_lwres = { static cfg_clausedef_t rndcconf_options_clauses[] = { - { "default-server", &cfg_type_astring, 0 }, { "default-key", &cfg_type_astring, 0 }, { "default-port", &cfg_type_uint32, 0 }, + { "default-server", &cfg_type_astring, 0 }, + { "default-source-address", &cfg_type_netaddr4wild, 0 }, + { "default-source-address-v6", &cfg_type_netaddr6wild, 0 }, { NULL, NULL, 0 } }; @@ -1701,14 +1705,16 @@ rndcconf_options_clausesets[] = { }; static cfg_type_t cfg_type_rndcconf_options = { - "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, - rndcconf_options_clausesets + "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map, + &cfg_rep_map, rndcconf_options_clausesets }; static cfg_clausedef_t rndcconf_server_clauses[] = { { "key", &cfg_type_astring, 0 }, { "port", &cfg_type_uint32, 0 }, + { "source-address", &cfg_type_netaddr4wild, 0 }, + { "source-address-v6", &cfg_type_netaddr6wild, 0 }, { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 }, { NULL, NULL, 0 } }; @@ -1720,8 +1726,8 @@ rndcconf_server_clausesets[] = { }; static cfg_type_t cfg_type_rndcconf_server = { - "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, - rndcconf_server_clausesets + "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map, + &cfg_rep_map, rndcconf_server_clausesets }; static cfg_clausedef_t diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 14223142ba..3fbda9bff4 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: parser.c,v 1.113 2004/05/15 03:37:34 jinmei Exp $ */ +/* $Id: parser.c,v 1.114 2004/07/23 04:15:26 marka Exp $ */ #include @@ -1766,14 +1766,21 @@ cfg_print_rawaddr(cfg_printer_t *pctx, isc_netaddr_t *na) { /* netaddr */ +static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; +static unsigned int netaddr4_flags = CFG_ADDR_V4OK; +static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK; +static unsigned int netaddr6_flags = CFG_ADDR_V6OK; +static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK; + static isc_result_t parse_netaddr(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; - UNUSED(type); + unsigned int flags = *(const unsigned int *)type->of; + CHECK(cfg_create_obj(pctx, type, &obj)); - CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK, &netaddr)); + CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); *ret = obj; return (ISC_R_SUCCESS); @@ -1782,9 +1789,57 @@ parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } +static void +cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { + const unsigned int *flagp = type->of; + int n = 0; + if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) + cfg_print_chars(pctx, "( ", 2); + if (*flagp & CFG_ADDR_V4OK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, ""); + n++; + } + if (*flagp & CFG_ADDR_V6OK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, ""); + n++; + } + if (*flagp & CFG_ADDR_WILDOK) { + if (n != 0) + cfg_print_chars(pctx, " | ", 3); + cfg_print_chars(pctx, "*", 1); + n++; + } + if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) + cfg_print_chars(pctx, " )", 2); +} + cfg_type_t cfg_type_netaddr = { - "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_terminal, - &cfg_rep_sockaddr, NULL + "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, + &cfg_rep_sockaddr, &netaddr_flags +}; + +cfg_type_t cfg_type_netaddr4 = { + "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, + &cfg_rep_sockaddr, &netaddr4_flags +}; + +cfg_type_t cfg_type_netaddr4wild = { + "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, + &cfg_rep_sockaddr, &netaddr4wild_flags +}; + +cfg_type_t cfg_type_netaddr6 = { + "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, + &cfg_rep_sockaddr, &netaddr6_flags +}; + +cfg_type_t cfg_type_netaddr6wild = { + "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, + &cfg_rep_sockaddr, &netaddr6wild_flags }; /* netprefix */