[tor-commits] [tor/master] Merge remote-tracking branch 'twstrike/parse_port_config_tests'

nickm at torproject.org nickm at torproject.org
Thu Jan 21 17:16:03 UTC 2016


commit cbed61d1280d5f85b1670a70c9d8d2331b919e80
Merge: ae3d2a9 f319231
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Jan 21 12:15:39 2016 -0500

    Merge remote-tracking branch 'twstrike/parse_port_config_tests'

 src/or/config.c        |   33 +-
 src/or/config.h        |   23 +-
 src/test/test_config.c |  856 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 889 insertions(+), 23 deletions(-)

diff --cc src/or/config.h
index 6e08f9d,33dc5df..920281a
--- a/src/or/config.h
+++ b/src/or/config.h
@@@ -152,14 -161,19 +163,24 @@@ STATIC int parse_transport_line(const o
                                  int server);
  STATIC int consider_adding_dir_servers(const or_options_t *options,
                                         const or_options_t *old_options);
 +STATIC void add_default_trusted_dir_authorities(dirinfo_type_t type);
  MOCK_DECL(STATIC void, add_default_fallback_dir_servers, (void));
 -STATIC int
 -parse_dir_fallback_line(const char *line,
 -                        int validate_only);
 -STATIC int
 -parse_port_config(smartlist_t *out,
 +STATIC int parse_dir_authority_line(const char *line,
 +                                    dirinfo_type_t required_type,
 +                                    int validate_only);
 +STATIC int parse_dir_fallback_line(const char *line, int validate_only);
 +STATIC int have_enough_mem_for_dircache(const or_options_t *options,
 +                                        size_t total_mem, char **msg);
++STATIC int parse_dir_fallback_line(const char *line,
++                                   int validate_only);
++STATIC int parse_port_config(smartlist_t *out,
+                   const config_line_t *ports,
+                   const config_line_t *listenaddrs,
+                   const char *portname,
+                   int listener_type,
+                   const char *defaultaddr,
+                   int defaultport,
+                   const unsigned flags);
  #endif
  
  #endif
diff --cc src/test/test_config.c
index 097fe15,6fdd7e7..58487d7
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@@ -15,12 -20,28 +20,30 @@@
  #include "test.h"
  #include "util.h"
  #include "address.h"
+ #include "connection_or.h"
+ #include "control.h"
+ #include "cpuworker.h"
++#include "dirserv.h"
+ #include "dirvote.h"
+ #include "dns.h"
  #include "entrynodes.h"
  #include "transports.h"
- #include "routerlist.h"
+ #include "ext_orport.h"
+ #include "geoip.h"
+ #include "hibernate.h"
+ #include "main.h"
 +#include "networkstatus.h"
+ #include "nodelist.h"
+ #include "policies.h"
+ #include "rendclient.h"
+ #include "rendservice.h"
  #include "router.h"
- #include "dirserv.h"
+ #include "routerlist.h"
+ #include "routerset.h"
+ #include "statefile.h"
+ #include "test.h"
+ #include "transports.h"
+ #include "util.h"
  
  static void
  test_config_addressmap(void *arg)
@@@ -3413,280 -3233,831 +3436,1105 @@@ test_config_adding_dir_servers(void *ar
    UNMOCK(add_default_fallback_dir_servers);
  }
  
 +static void
 +test_config_default_dir_servers(void *arg)
 +{
 +  or_options_t *opts = NULL;
 +  (void)arg;
 +  int trusted_count = 0;
 +  int fallback_count = 0;
 +
 +  /* new set of options should stop fallback parsing */
 +  opts = tor_malloc_zero(sizeof(or_options_t));
 +  opts->UseDefaultFallbackDirs = 0;
 +  /* set old_options to NULL to force dir update */
 +  consider_adding_dir_servers(opts, NULL);
 +  trusted_count = smartlist_len(router_get_trusted_dir_servers());
 +  fallback_count = smartlist_len(router_get_fallback_dir_servers());
 +  or_options_free(opts);
 +  opts = NULL;
 +
 +  /* assume a release will never go out with less than 7 authorities */
 +  tt_assert(trusted_count >= 7);
 +  /* if we disable the default fallbacks, there must not be any extra */
 +  tt_assert(fallback_count == trusted_count);
 +
 +  opts = tor_malloc_zero(sizeof(or_options_t));
 +  opts->UseDefaultFallbackDirs = 1;
 +  consider_adding_dir_servers(opts, opts);
 +  trusted_count = smartlist_len(router_get_trusted_dir_servers());
 +  fallback_count = smartlist_len(router_get_fallback_dir_servers());
 +  or_options_free(opts);
 +  opts = NULL;
 +
 +  /* assume a release will never go out with less than 7 authorities */
 +  tt_assert(trusted_count >= 7);
 +  /* XX/teor - allow for default fallbacks to be added without breaking
 +   * the unit tests. Set a minimum fallback count once the list is stable. */
 +  tt_assert(fallback_count >= trusted_count);
 +
 + done:
 +  or_options_free(opts);
 +}
 +
 +static int mock_router_pick_published_address_result = 0;
 +
 +static int
 +mock_router_pick_published_address(const or_options_t *options, uint32_t *addr)
 +{
 +  (void)options;
 +  (void)addr;
 +  return mock_router_pick_published_address_result;
 +}
 +
 +static int mock_router_my_exit_policy_is_reject_star_result = 0;
 +
 +static int
 +mock_router_my_exit_policy_is_reject_star(void)
 +{
 +  return mock_router_my_exit_policy_is_reject_star_result;
 +}
 +
 +static int mock_advertised_server_mode_result = 0;
 +
 +static int
 +mock_advertised_server_mode(void)
 +{
 +  return mock_advertised_server_mode_result;
 +}
 +
 +static routerinfo_t *mock_router_get_my_routerinfo_result = NULL;
 +
 +static const routerinfo_t *
 +mock_router_get_my_routerinfo(void)
 +{
 +  return mock_router_get_my_routerinfo_result;
 +}
 +
 +static void
 +test_config_directory_fetch(void *arg)
 +{
 +  (void)arg;
 +
 +  /* Test Setup */
 +  or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
 +  routerinfo_t routerinfo;
 +  memset(&routerinfo, 0, sizeof(routerinfo));
 +  mock_router_pick_published_address_result = -1;
 +  mock_router_my_exit_policy_is_reject_star_result = 1;
 +  mock_advertised_server_mode_result = 0;
 +  mock_router_get_my_routerinfo_result = NULL;
 +  MOCK(router_pick_published_address, mock_router_pick_published_address);
 +  MOCK(router_my_exit_policy_is_reject_star,
 +       mock_router_my_exit_policy_is_reject_star);
 +  MOCK(advertised_server_mode, mock_advertised_server_mode);
 +  MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo);
 +
 +  /* Clients can use multiple directory mirrors for bootstrap */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->ClientOnly = 1;
 +  tt_assert(server_mode(options) == 0);
 +  tt_assert(public_server_mode(options) == 0);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 1);
 +
 +  /* Bridge Clients can use multiple directory mirrors for bootstrap */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->UseBridges = 1;
 +  tt_assert(server_mode(options) == 0);
 +  tt_assert(public_server_mode(options) == 0);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 1);
 +
 +  /* Bridge Relays (Bridges) must act like clients, and use multiple
 +   * directory mirrors for bootstrap */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->BridgeRelay = 1;
 +  options->ORPort_set = 1;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 0);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 1);
 +
 +  /* Clients set to FetchDirInfoEarly must fetch it from the authorities,
 +   * but can use multiple authorities for bootstrap */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->FetchDirInfoEarly = 1;
 +  tt_assert(server_mode(options) == 0);
 +  tt_assert(public_server_mode(options) == 0);
 +  tt_assert(directory_fetches_from_authorities(options) == 1);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 1);
 +
 +  /* OR servers only fetch the consensus from the authorities when they don't
 +   * know their own address, but never use multiple directories for bootstrap
 +   */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->ORPort_set = 1;
 +
 +  mock_router_pick_published_address_result = -1;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 1);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  mock_router_pick_published_address_result = 0;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  /* Exit OR servers only fetch the consensus from the authorities when they
 +   * refuse unknown exits, but never use multiple directories for bootstrap
 +   */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->ORPort_set = 1;
 +  options->ExitRelay = 1;
 +  mock_router_pick_published_address_result = 0;
 +  mock_router_my_exit_policy_is_reject_star_result = 0;
 +  mock_advertised_server_mode_result = 1;
 +  mock_router_get_my_routerinfo_result = &routerinfo;
 +
 +  routerinfo.supports_tunnelled_dir_requests = 1;
 +
 +  options->RefuseUnknownExits = 1;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 1);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  options->RefuseUnknownExits = 0;
 +  mock_router_pick_published_address_result = 0;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  /* Dir servers fetch the consensus from the authorities, unless they are not
 +   * advertising themselves (hibernating) or have no routerinfo or are not
 +   * advertising their dirport, and never use multiple directories for
 +   * bootstrap. This only applies if they are also OR servers.
 +   * (We don't care much about the behaviour of non-OR directory servers.) */
 +  memset(options, 0, sizeof(or_options_t));
 +  options->DirPort_set = 1;
 +  options->ORPort_set = 1;
 +  options->DirCache = 1;
 +  mock_router_pick_published_address_result = 0;
 +  mock_router_my_exit_policy_is_reject_star_result = 1;
 +
 +  mock_advertised_server_mode_result = 1;
 +  routerinfo.dir_port = 1;
 +  mock_router_get_my_routerinfo_result = &routerinfo;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 1);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  mock_advertised_server_mode_result = 0;
 +  routerinfo.dir_port = 1;
 +  mock_router_get_my_routerinfo_result = &routerinfo;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  mock_advertised_server_mode_result = 1;
 +  mock_router_get_my_routerinfo_result = NULL;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  mock_advertised_server_mode_result = 1;
 +  routerinfo.dir_port = 0;
 +  routerinfo.supports_tunnelled_dir_requests = 0;
 +  mock_router_get_my_routerinfo_result = &routerinfo;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 0);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 +  mock_advertised_server_mode_result = 1;
 +  routerinfo.dir_port = 1;
 +  routerinfo.supports_tunnelled_dir_requests = 1;
 +  mock_router_get_my_routerinfo_result = &routerinfo;
 +  tt_assert(server_mode(options) == 1);
 +  tt_assert(public_server_mode(options) == 1);
 +  tt_assert(directory_fetches_from_authorities(options) == 1);
 +  tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
 +            == 0);
 +
 + done:
 +  tor_free(options);
 +  UNMOCK(router_pick_published_address);
 +  UNMOCK(router_get_my_routerinfo);
 +  UNMOCK(advertised_server_mode);
 +  UNMOCK(router_my_exit_policy_is_reject_star);
 +}
 +
 +static void
 +test_config_default_fallback_dirs(void *arg)
 +{
 +  const char *fallback[] = {
 +#include "../or/fallback_dirs.inc"
 +    NULL
 +  };
 +
 +  int n_included_fallback_dirs = 0;
 +  int n_added_fallback_dirs = 0;
 +
 +  (void)arg;
 +  clear_dir_servers();
 +
 +  while (fallback[n_included_fallback_dirs])
 +    n_included_fallback_dirs++;
 +
 +  add_default_fallback_dir_servers();
 +
 +  n_added_fallback_dirs = smartlist_len(router_get_fallback_dir_servers());
 +
 +  tt_assert(n_included_fallback_dirs == n_added_fallback_dirs);
 +
 +  done:
 +  clear_dir_servers();
 +}
 +
+ static config_line_t *
+ mock_config_line(const char *key, const char *val)
+ {
+   config_line_t *config_line = tor_malloc(sizeof(config_line_t));
+   memset(config_line, 0, sizeof(config_line_t));
+   config_line->key = tor_strdup(key);
+   config_line->value = tor_strdup(val);
+   return config_line;
+ }
+ 
+ static void
+ test_config_parse_port_config__listenaddress(void *data)
+ {
+   (void)data;
+   int ret;
+   config_line_t *config_listen_address = NULL, *config_listen_address2 = NULL,
+     *config_listen_address3 = NULL;
+   config_line_t *config_port1 = NULL, *config_port2 = NULL,
+     *config_port3 = NULL, *config_port4 = NULL, *config_port5 = NULL;
+   smartlist_t *slout = NULL;
+   port_cfg_t *port_cfg = NULL;
+ 
+   // Test basic invocation with no arguments
+   ret = parse_port_config(NULL, NULL, NULL, NULL, 0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Setup some test data
+   config_listen_address = mock_config_line("DNSListenAddress", "127.0.0.1");
+   config_listen_address2 = mock_config_line("DNSListenAddress", "x$$$:::345");
+   config_listen_address3 = mock_config_line("DNSListenAddress",
+                                             "127.0.0.1:1442");
+   config_port1 = mock_config_line("DNSPort", "42");
+   config_port2 = mock_config_line("DNSPort", "43");
+   config_port1->next = config_port2;
+   config_port3 = mock_config_line("DNSPort", "auto");
+   config_port4 = mock_config_line("DNSPort", "55542");
+   config_port5 = mock_config_line("DNSPort", "666777");
+ 
+   // Test failure when we have a ListenAddress line and several
+   // Port lines for the same portname
+   ret = parse_port_config(NULL, config_port1, config_listen_address, "DNS", 0,
+                           NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test case when we have a listen address, no default port and allow
+   // spurious listen address lines
+   ret = parse_port_config(NULL, NULL, config_listen_address, "DNS", 0, NULL,
+                           0, CL_PORT_ALLOW_EXTRA_LISTENADDR);
+   tt_int_op(ret, OP_EQ, 1);
+ 
+   // Test case when we have a listen address, no default port but doesn't
+   // allow spurious listen address lines
+   ret = parse_port_config(NULL, NULL, config_listen_address, "DNS", 0, NULL,
+                           0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test case when we have a listen address, and a port that points to auto,
+   // should use the AUTO port
+   slout = smartlist_new();
+   ret = parse_port_config(slout, config_port3, config_listen_address, "DNS",
+                           0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
+ 
+   // Test when we have a listen address and a custom port
+   ret = parse_port_config(slout, config_port4, config_listen_address, "DNS",
+                           0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 2);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 1);
+   tt_int_op(port_cfg->port, OP_EQ, 55542);
+ 
+   // Test when we have a listen address and an invalid custom port
+   ret = parse_port_config(slout, config_port5, config_listen_address, "DNS",
+                           0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test we get a server port configuration when asked for it
+   ret = parse_port_config(slout, NULL, config_listen_address, "DNS", 0, NULL,
+                           123, CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 4);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 2);
+   tt_int_op(port_cfg->port, OP_EQ, 123);
+   tt_int_op(port_cfg->server_cfg.no_listen, OP_EQ, 1);
+   tt_int_op(port_cfg->server_cfg.bind_ipv4_only, OP_EQ, 1);
+ 
+   // Test an invalid ListenAddress configuration
+   ret = parse_port_config(NULL, NULL, config_listen_address2, "DNS", 0, NULL,
+                           222, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test default to the port in the listen address if available
+   ret = parse_port_config(slout, config_port2, config_listen_address3, "DNS",
+                           0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 5);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 4);
+   tt_int_op(port_cfg->port, OP_EQ, 1442);
+ 
+   // Test we work correctly without an out, but with a listen address
+   // and a port
+   ret = parse_port_config(NULL, config_port2, config_listen_address, "DNS",
+                           0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test warning nonlocal control
+   ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
+                           CONN_TYPE_CONTROL_LISTENER, NULL, 0,
+                           CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test warning nonlocal ext or listener
+   ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
+                           CONN_TYPE_EXT_OR_LISTENER, NULL, 0,
+                           CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test warning nonlocal other
+   ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
+                           0, NULL, 0, CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test warning nonlocal control without an out
+   ret = parse_port_config(NULL, config_port2, config_listen_address, "DNS",
+                           CONN_TYPE_CONTROL_LISTENER, NULL, 0,
+                           CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+  done:
+   tor_free(config_listen_address);
+   tor_free(config_listen_address2);
+   tor_free(config_listen_address3);
+   tor_free(config_port1);
+   tor_free(config_port2);
+   tor_free(config_port3);
+   tor_free(config_port4);
+   tor_free(config_port5);
+   smartlist_free(slout);
+ }
+ 
+ static void
+ test_config_parse_port_config__ports__no_ports_given(void *data)
+ {
+   (void)data;
+   int ret;
+   smartlist_t *slout = NULL;
+   port_cfg_t *port_cfg = NULL;
+   config_line_t *config_port_invalid = NULL, *config_port_valid = NULL;
+ 
+   slout = smartlist_new();
+ 
+   // Test no defaultport, no defaultaddress and no out
+   ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test with defaultport, no defaultaddress and no out
+   ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, NULL, 42, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test no defaultport, with defaultaddress and no out
+   ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test with defaultport, with defaultaddress and no out
+   ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test no defaultport, no defaultaddress and with out
+   ret = parse_port_config(slout, NULL, NULL, "DNS", 0, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 0);
+ 
+   // Test with defaultport, no defaultaddress and with out
+   ret = parse_port_config(slout, NULL, NULL, "DNS", 0, NULL, 42, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 0);
+ 
+   // Test no defaultport, with defaultaddress and with out
+   ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 0);
+ 
+   // Test with defaultport, with defaultaddress and out, adds a new port cfg
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, 42);
+   tt_int_op(port_cfg->is_unix_addr, OP_EQ, 0);
+ 
+   // Test with defaultport, with defaultaddress and out, adds a new port cfg
+   // for a unix address
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "/foo/bar/unixdomain",
+                           42, CL_PORT_IS_UNIXSOCKET);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, 0);
+   tt_int_op(port_cfg->is_unix_addr, OP_EQ, 1);
+   tt_str_op(port_cfg->unix_addr, OP_EQ, "/foo/bar/unixdomain");
+ 
+  done:
+   smartlist_free(slout);
+   tor_free(config_port_invalid);
+   tor_free(config_port_valid);
+ }
+ 
+ static void
+ test_config_parse_port_config__ports__ports_given(void *data)
+ {
+   (void)data;
+   int ret;
+   smartlist_t *slout = NULL;
+   port_cfg_t *port_cfg = NULL;
+   config_line_t *config_port_invalid = NULL, *config_port_valid = NULL;
+   tor_addr_t addr;
+ 
+   slout = smartlist_new();
+ 
+   // Test error when encounters an invalid Port specification
+   config_port_invalid = mock_config_line("DNSPort", "");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test error when encounters an empty unix domain specification
+   tor_free(config_port_invalid);
+   config_port_invalid = mock_config_line("DNSPort", "unix:");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test error when encounters a unix domain specification but the listener
+   // doesnt support domain sockets
+   config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar");
+   ret = parse_port_config(NULL, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_DNS_LISTENER, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test valid unix domain
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, NULL, 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, 0);
+   tt_int_op(port_cfg->is_unix_addr, OP_EQ, 1);
+   tt_str_op(port_cfg->unix_addr, OP_EQ, "/tmp/foo/bar");
+ 
+   // Test failure if we have no ipv4 and no ipv6 (for unix domain sockets,
+   // this makes no sense - it should be fixed)
+   tor_free(config_port_invalid);
+   config_port_invalid = mock_config_line("DNSPort",
+                                          "unix:/tmp/foo/bar NoIPv4Traffic");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, NULL, 0,
+                           CL_PORT_TAKES_HOSTNAMES);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with no ipv4 but take ipv6 (for unix domain sockets, this
+   // makes no sense - it should be fixed)
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar "
+                                        "NoIPv4Traffic IPv6Traffic");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, NULL, 0,
+                           CL_PORT_TAKES_HOSTNAMES);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
+   tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
+ 
+   // Test success with both ipv4 and ipv6 (for unix domain sockets,
+   // this makes no sense - it should be fixed)
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar "
+                                        "IPv4Traffic IPv6Traffic");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, NULL, 0,
+                           CL_PORT_TAKES_HOSTNAMES);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
+ 
+   // Test failure if we specify world writable for an IP Port
+   tor_free(config_port_invalid);
+   config_port_invalid = mock_config_line("DNSPort", "42 WorldWritable");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test failure if we specify group writable for an IP Port
+   tor_free(config_port_invalid);
+   config_port_invalid = mock_config_line("DNSPort", "42 GroupWritable");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with only a port (this will fail without a default address)
+   tor_free(config_port_valid);
+   config_port_valid = mock_config_line("DNSPort", "42");
+   ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with only a port and isolate destination port
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IsolateDestPort");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT | ISO_DESTPORT);
+ 
+   // Test success with a negative isolate destination port, and plural
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 NoIsolateDestPorts");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT & ~ISO_DESTPORT);
+ 
+   // Test success with isolate destination address
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IsolateDestAddr");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT | ISO_DESTADDR);
+ 
+   // Test success with isolate socks AUTH
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IsolateSOCKSAuth");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT | ISO_SOCKSAUTH);
+ 
+   // Test success with isolate client protocol
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IsolateClientProtocol");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT | ISO_CLIENTPROTO);
+ 
+   // Test success with isolate client address
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IsolateClientAddr");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.isolation_flags, OP_EQ,
+             ISO_DEFAULT | ISO_CLIENTADDR);
+ 
+   // Test success with ignored unknown options
+   tor_free(config_port_valid);
+   config_port_valid = mock_config_line("DNSPort", "42 ThisOptionDoesntExist");
+   ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with no isolate socks AUTH
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 NoIsolateSOCKSAuth");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.3", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.socks_prefer_no_auth, OP_EQ, 1);
+ 
+   // Test success with prefer ipv6
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IPv6Traffic PreferIPv6");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, "127.0.0.42", 0,
+                           CL_PORT_TAKES_HOSTNAMES);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.prefer_ipv6, OP_EQ, 1);
+ 
+   // Test success with cache ipv4 DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 CacheIPv4DNS");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 0);
+ 
+   // Test success with cache ipv6 DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 CacheIPv6DNS");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 1);
+ 
+   // Test success with no cache ipv4 DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 NoCacheIPv4DNS");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 0);
+ 
+   // Test success with cache DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 CacheDNS");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, CL_PORT_TAKES_HOSTNAMES);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 1);
+ 
+   // Test success with use cached ipv4 DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 UseIPv4Cache");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv4_answers, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv6_answers, OP_EQ, 0);
+ 
+   // Test success with use cached ipv6 DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 UseIPv6Cache");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv4_answers, OP_EQ, 0);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv6_answers, OP_EQ, 1);
+ 
+   // Test success with use cached DNS
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 UseDNSCache");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv4_answers, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.use_cached_ipv6_answers, OP_EQ, 1);
+ 
+   // Test success with not preferring ipv6 automap
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 NoPreferIPv6Automap");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.prefer_ipv6_virtaddr, OP_EQ, 0);
+ 
+   // Test success with prefer SOCKS no auth
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 PreferSOCKSNoAuth");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.socks_prefer_no_auth, OP_EQ, 1);
+ 
+   // Test failure with both a zero port and a non-zero port
+   tor_free(config_port_invalid);
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "0");
+   config_port_valid = mock_config_line("DNSPort", "42");
+   config_port_invalid->next = config_port_valid;
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with warn non-local control
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_CONTROL_LISTENER, "127.0.0.42", 0,
+                           CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with warn non-local listener
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_EXT_OR_LISTENER, "127.0.0.42", 0,
+                           CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with warn non-local other
+   smartlist_clear(slout);
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with warn non-local other without out
+   ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
+   tt_int_op(ret, OP_EQ, 0);
+ 
+   // Test success with both ipv4 and ipv6 but without stream options
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 IPv4Traffic "
+                                        "IPv6Traffic");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.44", 0,
+                           CL_PORT_TAKES_HOSTNAMES |
+                           CL_PORT_NO_STREAM_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
+   tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
+ 
+   // Test failure for a SessionGroup argument with invalid value
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=invalid");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // TODO: this seems wrong. Shouldn't it be the other way around?
+   // Potential bug.
+   // Test failure for a SessionGroup argument with valid value but with stream
+   // options allowed
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.44", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test failure for more than one SessionGroup argument
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 "
+                                          "SessionGroup=321");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with a sessiongroup options
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->entry_cfg.session_group, OP_EQ, 1111122);
+ 
+   // Test success with a zero unix domain socket, and doesnt add it to out
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "0");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 0);
+ 
+   // Test success with a one unix domain socket, and doesnt add it to out
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "something");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->is_unix_addr, OP_EQ, 1);
+   tt_str_op(port_cfg->unix_addr, OP_EQ, "something");
+ 
+   // Test success with a port of auto - it uses the default address
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "auto");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
+   tor_addr_parse(&addr, "127.0.0.46");
+   tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ 
+   // Test success with parsing both an address and an auto port
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "127.0.0.122:auto");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
+   tor_addr_parse(&addr, "127.0.0.122");
+   tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ 
+   // Test failure when asked to parse an invalid address followed by auto
+   tor_free(config_port_invalid);
+   config_port_invalid = mock_config_line("DNSPort", "invalidstuff!!:auto");
+   ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with parsing both an address and a real port
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "127.0.0.123:656");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->port, OP_EQ, 656);
+   tor_addr_parse(&addr, "127.0.0.123");
+   tt_assert(tor_addr_eq(&port_cfg->addr, &addr))
+ 
+   // Test failure if we can't parse anything at all
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "something wrong");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test failure if we find both an address, a port and an auto
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "127.0.1.0:123:auto");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+                           "127.0.0.46", 0, 0);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test that default to group writeable default sets group writeable for
+   // domain socket
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "unix:/tmp/somewhere");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+                           CONN_TYPE_AP_LISTENER, "127.0.0.46", 0,
+                           CL_PORT_DFLT_GROUP_WRITABLE);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->is_group_writable, OP_EQ, 1);
+ 
+  done:
+   smartlist_free(slout);
+   tor_free(config_port_invalid);
+   tor_free(config_port_valid);
+ }
+ 
+ static void
+ test_config_parse_port_config__ports__server_options(void *data)
+ {
+   (void)data;
+   int ret;
+   smartlist_t *slout = NULL;
+   port_cfg_t *port_cfg = NULL;
+   config_line_t *config_port_invalid = NULL, *config_port_valid = NULL;
+ 
+   slout = smartlist_new();
+ 
+   // Test success with NoAdvertise option
+   tor_free(config_port_valid);
+   config_port_valid = mock_config_line("DNSPort",
+                                        "127.0.0.124:656 NoAdvertise");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+                           CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->server_cfg.no_advertise, OP_EQ, 1);
+   tt_int_op(port_cfg->server_cfg.no_listen, OP_EQ, 0);
+ 
+   // Test success with NoListen option
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+                           CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->server_cfg.no_advertise, OP_EQ, 0);
+   tt_int_op(port_cfg->server_cfg.no_listen, OP_EQ, 1);
+ 
+   // Test failure with both NoAdvertise and NoListen option
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen "
+                                          "NoAdvertise");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with IPv4Only
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 IPv4Only");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+                           CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->server_cfg.bind_ipv4_only, OP_EQ, 1);
+   tt_int_op(port_cfg->server_cfg.bind_ipv6_only, OP_EQ, 0);
+ 
+   // Test success with IPv6Only
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "[::1]:656 IPv6Only");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+                           CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+   port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
+   tt_int_op(port_cfg->server_cfg.bind_ipv4_only, OP_EQ, 0);
+   tt_int_op(port_cfg->server_cfg.bind_ipv6_only, OP_EQ, 1);
+ 
+   // Test failure with both IPv4Only and IPv6Only
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 IPv6Only "
+                                          "IPv4Only");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test success with invalid parameter
+   tor_free(config_port_valid);
+   smartlist_clear(slout);
+   config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 unknown");
+   ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+                           CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, 0);
+   tt_int_op(smartlist_len(slout), OP_EQ, 1);
+ 
+   // Test failure when asked to bind only to ipv6 but gets an ipv4 address
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort",
+                                          "127.0.0.124:656 IPv6Only");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+   // Test failure when asked to bind only to ipv4 but gets an ipv6 address
+   tor_free(config_port_invalid);
+   smartlist_clear(slout);
+   config_port_invalid = mock_config_line("DNSPort", "[::1]:656 IPv4Only");
+   ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+                           0, CL_PORT_SERVER_OPTIONS);
+   tt_int_op(ret, OP_EQ, -1);
+ 
+  done:
+   smartlist_free(slout);
+   tor_free(config_port_invalid);
+   tor_free(config_port_valid);
+ }
+ 
  #define CONFIG_TEST(name, flags)                          \
    { #name, test_config_ ## name, flags, NULL, NULL }
  
@@@ -3707,7 -4071,10 +4555,11 @@@ struct testcase_t config_tests[] = 
    CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
    CONFIG_TEST(write_to_data_subdir, TT_FORK),
    CONFIG_TEST(fix_my_family, 0),
 +  CONFIG_TEST(directory_fetch, 0),
+   CONFIG_TEST(parse_port_config__listenaddress, 0),
+   CONFIG_TEST(parse_port_config__ports__no_ports_given, 0),
+   CONFIG_TEST(parse_port_config__ports__server_options, 0),
+   CONFIG_TEST(parse_port_config__ports__ports_given, 0),
    END_OF_TESTCASES
  };
  



More information about the tor-commits mailing list