Browse Source

Merge remote-tracking branch 'origin/maint-0.2.2'

Conflicts:
	src/or/config.c
	src/or/dirserv.c
	src/or/or.h
Nick Mathewson 13 years ago
parent
commit
600744b4be
13 changed files with 320 additions and 70 deletions
  1. 14 0
      changes/feature3076
  2. 33 14
      doc/tor.1.txt
  3. 30 0
      src/common/address.c
  4. 1 0
      src/common/address.h
  5. 30 31
      src/or/config.c
  6. 51 16
      src/or/connection.c
  7. 105 0
      src/or/control.c
  8. 2 0
      src/or/control.h
  9. 4 3
      src/or/dirserv.c
  10. 4 2
      src/or/main.c
  11. 9 0
      src/or/or.h
  12. 34 4
      src/or/router.c
  13. 3 0
      src/or/router.h

+ 14 - 0
changes/feature3076

@@ -0,0 +1,14 @@
+  o Minor features
+    - The options SocksPort, ControlPort, and so on now all accept an
+      optional value "auto" that opens a socket on an OS-selected port.
+  o Minor features (controller)
+    - GETINFO net/listeners/(type) now returns a list of the addresses
+      and ports that are bound for listeners for a given connection
+      type.  This is useful for if the user has selected SocksPort
+      "auto", and you need to know which port got chosen.
+    - There is a ControlPortWriteToFile option that tells Tor to write
+      its actual control port or ports to a chosen file.  If the option
+      ControlPortFileGroupReadable is set, the file is created as
+      group-readable.
+
+

+ 33 - 14
doc/tor.1.txt

@@ -145,13 +145,15 @@ Other options can be specified either on the command-line (--option
     all sockets will be set to this limit. Must be a value between 2048 and
     all sockets will be set to this limit. Must be a value between 2048 and
     262144, in 1024 byte increments. Default of 8192 is recommended.
     262144, in 1024 byte increments. Default of 8192 is recommended.
 
 
-**ControlPort** __Port__::
+**ControlPort** __PORT__|**auto**::
     If set, Tor will accept connections on this port and allow those
     If set, Tor will accept connections on this port and allow those
     connections to control the Tor process using the Tor Control Protocol
     connections to control the Tor process using the Tor Control Protocol
     (described in control-spec.txt). Note: unless you also specify one of
     (described in control-spec.txt). Note: unless you also specify one of
-    **HashedControlPassword** or **CookieAuthentication**, setting this option will
+    **HashedControlPassword** or **CookieAuthentication**, setting this
+    option will
     cause Tor to allow any process on the local host to control it. This
     cause Tor to allow any process on the local host to control it. This
     option is required for many Tor controllers; most use the value of 9051.
     option is required for many Tor controllers; most use the value of 9051.
+    Set it to "auto" to have Tor pick a port for you. (Default: 0).
 
 
 **ControlListenAddress** __IP__[:__PORT__]::
 **ControlListenAddress** __IP__[:__PORT__]::
     Bind the controller listener to this address. If you specify a port, bind
     Bind the controller listener to this address. If you specify a port, bind
@@ -189,6 +191,16 @@ Other options can be specified either on the command-line (--option
     the default GID. [Making the file readable by other groups is not yet
     the default GID. [Making the file readable by other groups is not yet
     implemented; let us know if you need this for some reason.] (Default: 0).
     implemented; let us know if you need this for some reason.] (Default: 0).
 
 
+**ControlPortWriteToFile** __Path__::
+    If set, Tor writes the address and port of any control port it opens to
+    this address.  Usable by controllers to learn the actual control port
+    when ControlPort is set to "auto".
+
+**ControlPortFileGroupReadable** **0**|**1**::
+    If this option is set to 0, don't allow the filesystem group to read the
+    control port file. If the option is set to 1, make the control port
+    file readable by the default GID. (Default: 0).
+
 **DataDirectory** __DIR__::
 **DataDirectory** __DIR__::
     Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
     Store working data in DIR (Default: @LOCALSTATEDIR@/lib/tor)
 
 
@@ -665,10 +677,11 @@ The following options are useful only for clients (that is, if
     the same circuit. Currently, two addresses are "too close" if they lie in
     the same circuit. Currently, two addresses are "too close" if they lie in
     the same /16 range. (Default: 1)
     the same /16 range. (Default: 1)
 
 
-**SocksPort** __PORT__::
+**SocksPort** __PORT__|**auto**::
     Advertise this port to listen for connections from Socks-speaking
     Advertise this port to listen for connections from Socks-speaking
     applications. Set this to 0 if you don't want to allow application
     applications. Set this to 0 if you don't want to allow application
-    connections. (Default: 9050)
+    connections via SOCKS. Set it to "auto" to have Tor pick a port for
+    you. (Default: 9050)
 
 
 **SocksListenAddress** __IP__[:__PORT__]::
 **SocksListenAddress** __IP__[:__PORT__]::
     Bind to this address to listen for connections from Socks-speaking
     Bind to this address to listen for connections from Socks-speaking
@@ -777,23 +790,25 @@ The following options are useful only for clients (that is, if
     operating as a relay, and it will never use the public key step if it
     operating as a relay, and it will never use the public key step if it
     doesn't yet know the onion key of the first hop. (Default: 1)
     doesn't yet know the onion key of the first hop. (Default: 1)
 
 
-**TransPort** __PORT__::
+**TransPort** __PORT__|**auto**::
     If non-zero, enables transparent proxy support on __PORT__ (by convention,
     If non-zero, enables transparent proxy support on __PORT__ (by convention,
     9040). Requires OS support for transparent proxies, such as BSDs' pf or
     9040). Requires OS support for transparent proxies, such as BSDs' pf or
     Linux's IPTables. If you're planning to use Tor as a transparent proxy for
     Linux's IPTables. If you're planning to use Tor as a transparent proxy for
     a network, you'll want to examine and change VirtualAddrNetwork from the
     a network, you'll want to examine and change VirtualAddrNetwork from the
     default setting. You'll also want to set the TransListenAddress option for
     default setting. You'll also want to set the TransListenAddress option for
-    the network you'd like to proxy. (Default: 0).
+    the network you'd like to proxy.  Set it to "auto" to have Tor pick a
+    port for you.  (Default: 0).
 
 
 **TransListenAddress** __IP__[:__PORT__]::
 **TransListenAddress** __IP__[:__PORT__]::
     Bind to this address to listen for transparent proxy connections. (Default:
     Bind to this address to listen for transparent proxy connections. (Default:
     127.0.0.1). This is useful for exporting a transparent proxy server to an
     127.0.0.1). This is useful for exporting a transparent proxy server to an
     entire network.
     entire network.
 
 
-**NATDPort** __PORT__::
+**NATDPort** __PORT__|**auto**::
     Allow old versions of ipfw (as included in old versions of FreeBSD, etc.)
     Allow old versions of ipfw (as included in old versions of FreeBSD, etc.)
     to send connections through Tor using the NATD protocol. This option is
     to send connections through Tor using the NATD protocol. This option is
-    only for people who cannot use TransPort.
+    only for people who cannot use TransPort.  Set it to "auto" to have Tor
+    pick a port for you. (Default: 0)
 
 
 **NATDListenAddress** __IP__[:__PORT__]::
 **NATDListenAddress** __IP__[:__PORT__]::
     Bind to this address to listen for NATD connections. (Default: 127.0.0.1).
     Bind to this address to listen for NATD connections. (Default: 127.0.0.1).
@@ -809,9 +824,10 @@ The following options are useful only for clients (that is, if
     A comma-separated list of suffixes to use with **AutomapHostsOnResolve**.
     A comma-separated list of suffixes to use with **AutomapHostsOnResolve**.
     The "." suffix is equivalent to "all addresses." (Default: .exit,.onion).
     The "." suffix is equivalent to "all addresses." (Default: .exit,.onion).
 
 
-**DNSPort** __PORT__::
+**DNSPort** __PORT__|**auto**::
     If non-zero, Tor listens for UDP DNS requests on this port and resolves
     If non-zero, Tor listens for UDP DNS requests on this port and resolves
-    them anonymously. (Default: 0).
+    them anonymously.  Set it to "auto" to have Tor pick a port for
+    you. (Default: 0).
 
 
 **DNSListenAddress** __IP__[:__PORT__]::
 **DNSListenAddress** __IP__[:__PORT__]::
     Bind to this address to listen for DNS connections. (Default: 127.0.0.1).
     Bind to this address to listen for DNS connections. (Default: 127.0.0.1).
@@ -965,8 +981,10 @@ is non-zero):
     parallelizable operations.  If this is set to 0, Tor will try to detect
     parallelizable operations.  If this is set to 0, Tor will try to detect
     how many CPUs you have, defaulting to 1 if it can't tell.  (Default: 0)
     how many CPUs you have, defaulting to 1 if it can't tell.  (Default: 0)
 
 
-**ORPort** __PORT__::
-    Advertise this port to listen for connections from Tor clients and servers.
+**ORPort** __PORT__|**auto**::
+    Advertise this port to listen for connections from Tor clients and
+    servers.  This option is required to be a Tor server.
+    Set it to "auto" to have Tor pick a port for you. (Default: 0).
 
 
 **ORListenAddress** __IP__[:__PORT__]::
 **ORListenAddress** __IP__[:__PORT__]::
     Bind to this IP address to listen for connections from Tor clients and
     Bind to this IP address to listen for connections from Tor clients and
@@ -1199,8 +1217,9 @@ if DirPort is non-zero):
     Minimum uptime of a v2 hidden service directory to be accepted as such by
     Minimum uptime of a v2 hidden service directory to be accepted as such by
     authoritative directories. (Default: 24 hours)
     authoritative directories. (Default: 24 hours)
 
 
-**DirPort** __PORT__::
-    Advertise the directory service on this port.
+**DirPort** __PORT__|**auto**::
+    If this option is nonzero, advertise the directory service on this port.
+    Set it to "auto" to have Tor pick a port for you.  (Default: 0)
 
 
 **DirListenAddress** __IP__[:__PORT__]::
 **DirListenAddress** __IP__[:__PORT__]::
     Bind the directory service to this address. If you specify a port, bind to
     Bind the directory service to this address. If you specify a port, bind to

+ 30 - 0
src/common/address.c

@@ -43,6 +43,9 @@
 #ifdef HAVE_SYS_PARAM_H
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h> /* FreeBSD needs this to know what version it is */
 #include <sys/param.h> /* FreeBSD needs this to know what version it is */
 #endif
 #endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
 #include <stdarg.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -120,6 +123,33 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
   return 0;
   return 0;
 }
 }
 
 
+/** Return a newly allocated string holding the address described in
+ * <b>sa</b>.  AF_UNIX, AF_UNSPEC, AF_INET, and AF_INET6 are supported. */
+char *
+tor_sockaddr_to_str(const struct sockaddr *sa)
+{
+  char address[TOR_ADDR_BUF_LEN];
+  char *result;
+  tor_addr_t addr;
+  uint16_t port;
+#ifdef HAVE_SYS_UN_H
+  if (sa->sa_family == AF_UNIX) {
+    struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+    tor_asprintf(&result, "unix:%s", s_un->sun_path);
+    return result;
+  }
+#endif
+  if (sa->sa_family == AF_UNSPEC)
+    return tor_strdup("unspec");
+
+  if (tor_addr_from_sockaddr(&addr, sa, &port) < 0)
+    return NULL;
+  if (! tor_addr_to_str(address, &addr, sizeof(address), 1))
+    return NULL;
+  tor_asprintf(&result, "%s:%d", address, (int)port);
+  return result;
+}
+
 /** Set address <b>a</b> to the unspecified address.  This address belongs to
 /** Set address <b>a</b> to the unspecified address.  This address belongs to
  * no family. */
  * no family. */
 void
 void

+ 1 - 0
src/common/address.h

@@ -44,6 +44,7 @@ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
 int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
 int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
                            uint16_t *port_out);
                            uint16_t *port_out);
 void tor_addr_make_unspec(tor_addr_t *a);
 void tor_addr_make_unspec(tor_addr_t *a);
+char *tor_sockaddr_to_str(const struct sockaddr *sa);
 
 
 /** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
 /** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
  * an IPv6 address. */
  * an IPv6 address. */

+ 30 - 31
src/or/config.c

@@ -43,6 +43,8 @@ typedef enum config_type_t {
   CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
   CONFIG_TYPE_STRING = 0,   /**< An arbitrary string. */
   CONFIG_TYPE_FILENAME,     /**< A filename: some prefixes get expanded. */
   CONFIG_TYPE_FILENAME,     /**< A filename: some prefixes get expanded. */
   CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
   CONFIG_TYPE_UINT,         /**< A non-negative integer less than MAX_INT */
+  CONFIG_TYPE_PORT,         /**< A port from 1...65535, 0 for "not set", or
+                             * "auto".  */
   CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
   CONFIG_TYPE_INTERVAL,     /**< A number of seconds, with optional units*/
   CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
   CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional
                               * units */
                               * units */
@@ -208,7 +210,9 @@ static config_var_t _option_vars[] = {
   V(ConstrainedSockSize,         MEMUNIT,  "8192"),
   V(ConstrainedSockSize,         MEMUNIT,  "8192"),
   V(ContactInfo,                 STRING,   NULL),
   V(ContactInfo,                 STRING,   NULL),
   V(ControlListenAddress,        LINELIST, NULL),
   V(ControlListenAddress,        LINELIST, NULL),
-  V(ControlPort,                 UINT,     "0"),
+  V(ControlPort,                 PORT,     "0"),
+  V(ControlPortFileGroupReadable,BOOL,     "0"),
+  V(ControlPortWriteToFile,      FILENAME, NULL),
   V(ControlSocket,               LINELIST, NULL),
   V(ControlSocket,               LINELIST, NULL),
   V(CookieAuthentication,        BOOL,     "0"),
   V(CookieAuthentication,        BOOL,     "0"),
   V(CookieAuthFileGroupReadable, BOOL,     "0"),
   V(CookieAuthFileGroupReadable, BOOL,     "0"),
@@ -221,7 +225,7 @@ static config_var_t _option_vars[] = {
   V(DirListenAddress,            LINELIST, NULL),
   V(DirListenAddress,            LINELIST, NULL),
   OBSOLETE("DirFetchPeriod"),
   OBSOLETE("DirFetchPeriod"),
   V(DirPolicy,                   LINELIST, NULL),
   V(DirPolicy,                   LINELIST, NULL),
-  V(DirPort,                     UINT,     "0"),
+  V(DirPort,                     PORT,     "0"),
   V(DirPortFrontPage,            FILENAME, NULL),
   V(DirPortFrontPage,            FILENAME, NULL),
   OBSOLETE("DirPostPeriod"),
   OBSOLETE("DirPostPeriod"),
   OBSOLETE("DirRecordUsageByCountry"),
   OBSOLETE("DirRecordUsageByCountry"),
@@ -232,7 +236,7 @@ static config_var_t _option_vars[] = {
   VAR("DirServer",               LINELIST, DirServers, NULL),
   VAR("DirServer",               LINELIST, DirServers, NULL),
   V(DisableAllSwap,              BOOL,     "0"),
   V(DisableAllSwap,              BOOL,     "0"),
   V(DisableIOCP,                 BOOL,     "1"),
   V(DisableIOCP,                 BOOL,     "1"),
-  V(DNSPort,                     UINT,     "0"),
+  V(DNSPort,                     PORT,     "0"),
   V(DNSListenAddress,            LINELIST, NULL),
   V(DNSListenAddress,            LINELIST, NULL),
   V(DownloadExtraInfo,           BOOL,     "0"),
   V(DownloadExtraInfo,           BOOL,     "0"),
   V(EnforceDistinctSubnets,      BOOL,     "1"),
   V(EnforceDistinctSubnets,      BOOL,     "1"),
@@ -313,7 +317,7 @@ static config_var_t _option_vars[] = {
   V(NewCircuitPeriod,            INTERVAL, "30 seconds"),
   V(NewCircuitPeriod,            INTERVAL, "30 seconds"),
   VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
   VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
   V(NATDListenAddress,           LINELIST, NULL),
   V(NATDListenAddress,           LINELIST, NULL),
-  V(NATDPort,                    UINT,     "0"),
+  V(NATDPort,                    PORT,     "0"),
   V(Nickname,                    STRING,   NULL),
   V(Nickname,                    STRING,   NULL),
   V(WarnUnsafeSocks,              BOOL,     "1"),
   V(WarnUnsafeSocks,              BOOL,     "1"),
   OBSOLETE("NoPublish"),
   OBSOLETE("NoPublish"),
@@ -321,7 +325,7 @@ static config_var_t _option_vars[] = {
   V(NumCPUs,                     UINT,     "0"),
   V(NumCPUs,                     UINT,     "0"),
   V(NumEntryGuards,              UINT,     "3"),
   V(NumEntryGuards,              UINT,     "3"),
   V(ORListenAddress,             LINELIST, NULL),
   V(ORListenAddress,             LINELIST, NULL),
-  V(ORPort,                      UINT,     "0"),
+  V(ORPort,                      PORT,     "0"),
   V(OutboundBindAddress,         STRING,   NULL),
   V(OutboundBindAddress,         STRING,   NULL),
   OBSOLETE("PathlenCoinWeight"),
   OBSOLETE("PathlenCoinWeight"),
   V(PerConnBWBurst,              MEMUNIT,  "0"),
   V(PerConnBWBurst,              MEMUNIT,  "0"),
@@ -366,7 +370,7 @@ static config_var_t _option_vars[] = {
   V(ShutdownWaitLength,          INTERVAL, "30 seconds"),
   V(ShutdownWaitLength,          INTERVAL, "30 seconds"),
   V(SocksListenAddress,          LINELIST, NULL),
   V(SocksListenAddress,          LINELIST, NULL),
   V(SocksPolicy,                 LINELIST, NULL),
   V(SocksPolicy,                 LINELIST, NULL),
-  V(SocksPort,                   UINT,     "9050"),
+  V(SocksPort,                   PORT,     "9050"),
   V(SocksTimeout,                INTERVAL, "2 minutes"),
   V(SocksTimeout,                INTERVAL, "2 minutes"),
   OBSOLETE("StatusFetchPeriod"),
   OBSOLETE("StatusFetchPeriod"),
   V(StrictNodes,                 BOOL,     "0"),
   V(StrictNodes,                 BOOL,     "0"),
@@ -377,7 +381,7 @@ static config_var_t _option_vars[] = {
   V(TrackHostExitsExpire,        INTERVAL, "30 minutes"),
   V(TrackHostExitsExpire,        INTERVAL, "30 minutes"),
   OBSOLETE("TrafficShaping"),
   OBSOLETE("TrafficShaping"),
   V(TransListenAddress,          LINELIST, NULL),
   V(TransListenAddress,          LINELIST, NULL),
-  V(TransPort,                   UINT,     "0"),
+  V(TransPort,                   PORT,     "0"),
   V(TunnelDirConns,              BOOL,     "1"),
   V(TunnelDirConns,              BOOL,     "1"),
   V(UpdateBridgesFromAuthority,  BOOL,     "0"),
   V(UpdateBridgesFromAuthority,  BOOL,     "0"),
   V(UseBridges,                  BOOL,     "0"),
   V(UseBridges,                  BOOL,     "0"),
@@ -576,7 +580,7 @@ static int or_state_validate(or_state_t *old_options, or_state_t *options,
 static int or_state_load(void);
 static int or_state_load(void);
 static int options_init_logs(or_options_t *options, int validate_only);
 static int options_init_logs(or_options_t *options, int validate_only);
 
 
-static int is_listening_on_low_port(uint16_t port_option,
+static int is_listening_on_low_port(int port_option,
                                     const config_line_t *listen_options);
                                     const config_line_t *listen_options);
 
 
 static uint64_t config_parse_memunit(const char *s, int *ok);
 static uint64_t config_parse_memunit(const char *s, int *ok);
@@ -1723,8 +1727,16 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
 
 
   switch (var->type) {
   switch (var->type) {
 
 
+  case CONFIG_TYPE_PORT:
+    if (!strcasecmp(c->value, "auto")) {
+      *(int *)lvalue = CFG_AUTO_PORT;
+      break;
+    }
+    /* fall through */
   case CONFIG_TYPE_UINT:
   case CONFIG_TYPE_UINT:
-    i = (int)tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
+    i = (int)tor_parse_long(c->value, 10, 0,
+                            var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
+                            &ok, NULL);
     if (!ok) {
     if (!ok) {
       tor_asprintf(msg,
       tor_asprintf(msg,
           "Int keyword '%s %s' is malformed or out of bounds.",
           "Int keyword '%s %s' is malformed or out of bounds.",
@@ -2058,6 +2070,12 @@ get_assigned_option(config_format_t *fmt, void *options,
       }
       }
       escape_val = 0; /* Can't need escape. */
       escape_val = 0; /* Can't need escape. */
       break;
       break;
+    case CONFIG_TYPE_PORT:
+      if (*(int*)value == CFG_AUTO_PORT) {
+        result->value = tor_strdup("auto");
+        escape_val = 0;
+        break;
+      }
     case CONFIG_TYPE_INTERVAL:
     case CONFIG_TYPE_INTERVAL:
     case CONFIG_TYPE_MSEC_INTERVAL:
     case CONFIG_TYPE_MSEC_INTERVAL:
     case CONFIG_TYPE_UINT:
     case CONFIG_TYPE_UINT:
@@ -2297,6 +2315,7 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
     case CONFIG_TYPE_INTERVAL:
     case CONFIG_TYPE_INTERVAL:
     case CONFIG_TYPE_MSEC_INTERVAL:
     case CONFIG_TYPE_MSEC_INTERVAL:
     case CONFIG_TYPE_UINT:
     case CONFIG_TYPE_UINT:
+    case CONFIG_TYPE_PORT:
     case CONFIG_TYPE_BOOL:
     case CONFIG_TYPE_BOOL:
       *(int*)lvalue = 0;
       *(int*)lvalue = 0;
       break;
       break;
@@ -2677,7 +2696,7 @@ options_init(or_options_t *options)
  * it is, or 0 if it isn't or the concept of a low port isn't applicable for
  * it is, or 0 if it isn't or the concept of a low port isn't applicable for
  * the platform we're on. */
  * the platform we're on. */
 static int
 static int
-is_listening_on_low_port(uint16_t port_option,
+is_listening_on_low_port(int port_option,
                          const config_line_t *listen_options)
                          const config_line_t *listen_options)
 {
 {
 #ifdef MS_WINDOWS
 #ifdef MS_WINDOWS
@@ -2926,9 +2945,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
   tor_assert(msg);
   tor_assert(msg);
   *msg = NULL;
   *msg = NULL;
 
 
-  if (options->ORPort < 0 || options->ORPort > 65535)
-    REJECT("ORPort option out of bounds.");
-
   if (server_mode(options) &&
   if (server_mode(options) &&
       (!strcmpstart(uname, "Windows 95") ||
       (!strcmpstart(uname, "Windows 95") ||
        !strcmpstart(uname, "Windows 98") ||
        !strcmpstart(uname, "Windows 98") ||
@@ -3037,18 +3053,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
     REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
     REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
 #endif
 #endif
 
 
-  if (options->SocksPort < 0 || options->SocksPort > 65535)
-    REJECT("SocksPort option out of bounds.");
-
-  if (options->DNSPort < 0 || options->DNSPort > 65535)
-    REJECT("DNSPort option out of bounds.");
-
-  if (options->TransPort < 0 || options->TransPort > 65535)
-    REJECT("TransPort option out of bounds.");
-
-  if (options->NATDPort < 0 || options->NATDPort > 65535)
-    REJECT("NATDPort option out of bounds.");
-
   if (options->SocksPort == 0 && options->TransPort == 0 &&
   if (options->SocksPort == 0 && options->TransPort == 0 &&
       options->NATDPort == 0 && options->ORPort == 0 &&
       options->NATDPort == 0 && options->ORPort == 0 &&
       options->DNSPort == 0 && !options->RendConfigLines)
       options->DNSPort == 0 && !options->RendConfigLines)
@@ -3057,12 +3061,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
         "undefined, and there aren't any hidden services configured.  "
         "undefined, and there aren't any hidden services configured.  "
         "Tor will still run, but probably won't do anything.");
         "Tor will still run, but probably won't do anything.");
 
 
-  if (options->ControlPort < 0 || options->ControlPort > 65535)
-    REJECT("ControlPort option out of bounds.");
-
-  if (options->DirPort < 0 || options->DirPort > 65535)
-    REJECT("DirPort option out of bounds.");
-
 #ifndef USE_TRANSPARENT
 #ifndef USE_TRANSPARENT
   if (options->TransPort || options->TransListenAddress)
   if (options->TransPort || options->TransListenAddress)
     REJECT("TransPort and TransListenAddress are disabled in this build.");
     REJECT("TransPort and TransListenAddress are disabled in this build.");
@@ -5415,6 +5413,7 @@ getinfo_helper_config(control_connection_t *conn,
         case CONFIG_TYPE_STRING: type = "String"; break;
         case CONFIG_TYPE_STRING: type = "String"; break;
         case CONFIG_TYPE_FILENAME: type = "Filename"; break;
         case CONFIG_TYPE_FILENAME: type = "Filename"; break;
         case CONFIG_TYPE_UINT: type = "Integer"; break;
         case CONFIG_TYPE_UINT: type = "Integer"; break;
+        case CONFIG_TYPE_PORT: type = "Port"; break;
         case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break;
         case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break;
         case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break;
         case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break;
         case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
         case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;

+ 51 - 16
src/or/connection.c

@@ -41,7 +41,7 @@
 #endif
 #endif
 
 
 static connection_t *connection_create_listener(
 static connection_t *connection_create_listener(
-                               struct sockaddr *listensockaddr,
+                               const struct sockaddr *listensockaddr,
                                socklen_t listensocklen, int type,
                                socklen_t listensocklen, int type,
                                char* address);
                                char* address);
 static void connection_init(time_t now, connection_t *conn, int type,
 static void connection_init(time_t now, connection_t *conn, int type,
@@ -802,7 +802,7 @@ connection_expire_held_open(void)
  * The listenaddr struct has to be freed by the caller.
  * The listenaddr struct has to be freed by the caller.
  */
  */
 static struct sockaddr_in *
 static struct sockaddr_in *
-create_inet_sockaddr(const char *listenaddress, uint16_t listenport,
+create_inet_sockaddr(const char *listenaddress, int listenport,
                      char **readable_address, socklen_t *socklen_out) {
                      char **readable_address, socklen_t *socklen_out) {
   struct sockaddr_in *listenaddr = NULL;
   struct sockaddr_in *listenaddr = NULL;
   uint32_t addr;
   uint32_t addr;
@@ -814,8 +814,10 @@ create_inet_sockaddr(const char *listenaddress, uint16_t listenport,
              "Error parsing/resolving ListenAddress %s", listenaddress);
              "Error parsing/resolving ListenAddress %s", listenaddress);
     goto err;
     goto err;
   }
   }
-  if (usePort==0)
-    usePort = listenport;
+  if (usePort==0) {
+    if (listenport != CFG_AUTO_PORT)
+      usePort = listenport;
+  }
 
 
   listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
   listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
   listenaddr->sin_addr.s_addr = htonl(addr);
   listenaddr->sin_addr.s_addr = htonl(addr);
@@ -901,12 +903,13 @@ warn_too_many_conns(void)
  * to the conn.
  * to the conn.
  */
  */
 static connection_t *
 static connection_t *
-connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
+connection_create_listener(const struct sockaddr *listensockaddr,
+                           socklen_t socklen,
                            int type, char* address)
                            int type, char* address)
 {
 {
   connection_t *conn;
   connection_t *conn;
   int s; /* the socket we're going to make */
   int s; /* the socket we're going to make */
-  uint16_t usePort = 0;
+  uint16_t usePort = 0, gotPort = 0;
   int start_reading = 0;
   int start_reading = 0;
 
 
   if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
   if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
@@ -915,6 +918,7 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
   }
   }
 
 
   if (listensockaddr->sa_family == AF_INET) {
   if (listensockaddr->sa_family == AF_INET) {
+    tor_addr_t addr;
     int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
     int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
 #ifndef MS_WINDOWS
 #ifndef MS_WINDOWS
     int one=1;
     int one=1;
@@ -922,11 +926,10 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
     if (is_tcp)
     if (is_tcp)
       start_reading = 1;
       start_reading = 1;
 
 
-    usePort = ntohs( (uint16_t)
-                     ((struct sockaddr_in *)listensockaddr)->sin_port);
+    tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
 
 
     log_notice(LD_NET, "Opening %s on %s:%d",
     log_notice(LD_NET, "Opening %s on %s:%d",
-               conn_type_to_string(type), address, usePort);
+               conn_type_to_string(type), fmt_addr(&addr), usePort);
 
 
     s = tor_open_socket(PF_INET,
     s = tor_open_socket(PF_INET,
                         is_tcp ? SOCK_STREAM : SOCK_DGRAM,
                         is_tcp ? SOCK_STREAM : SOCK_DGRAM,
@@ -964,6 +967,21 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
         goto err;
         goto err;
       }
       }
     }
     }
+
+    if (usePort != 0) {
+      gotPort = usePort;
+    } else {
+      tor_addr_t addr2;
+      struct sockaddr_storage ss;
+      socklen_t ss_len=sizeof(ss);
+      if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) {
+        log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s",
+                 conn_type_to_string(type),
+                 tor_socket_strerror(tor_socket_errno(s)));
+        gotPort = 0;
+      }
+      tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
+    }
 #ifdef HAVE_SYS_UN_H
 #ifdef HAVE_SYS_UN_H
   } else if (listensockaddr->sa_family == AF_UNIX) {
   } else if (listensockaddr->sa_family == AF_UNIX) {
     start_reading = 1;
     start_reading = 1;
@@ -1011,7 +1029,7 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
   conn->socket_family = listensockaddr->sa_family;
   conn->socket_family = listensockaddr->sa_family;
   conn->s = s;
   conn->s = s;
   conn->address = tor_strdup(address);
   conn->address = tor_strdup(address);
-  conn->port = usePort;
+  conn->port = gotPort;
 
 
   if (connection_add(conn) < 0) { /* no space, forget it */
   if (connection_add(conn) < 0) { /* no space, forget it */
     log_warn(LD_NET,"connection_add for listener failed. Giving up.");
     log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1019,8 +1037,12 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
     goto err;
     goto err;
   }
   }
 
 
-  log_debug(LD_NET,"%s listening on port %u.",
-            conn_type_to_string(type), usePort);
+  log_fn(usePort==gotPort ? LOG_DEBUG : LOG_NOTICE, LD_NET,
+         "%s listening on port %u.",
+         conn_type_to_string(type), gotPort);
+
+  if (type == CONN_TYPE_CONTROL_LISTENER)
+    control_ports_write_to_file();
 
 
   conn->state = LISTENER_STATE_READY;
   conn->state = LISTENER_STATE_READY;
   if (start_reading) {
   if (start_reading) {
@@ -1809,10 +1831,23 @@ retry_listeners(int type, config_line_t *cfg,
             if (!parse_addr_port(LOG_WARN,
             if (!parse_addr_port(LOG_WARN,
                                  wanted->value, &address, NULL, &port)) {
                                  wanted->value, &address, NULL, &port)) {
               int addr_matches = !strcasecmp(address, conn->address);
               int addr_matches = !strcasecmp(address, conn->address);
+              int port_matches;
               tor_free(address);
               tor_free(address);
-              if (! port)
-                port = port_option;
-              if (port == conn->port && addr_matches) {
+              if (port) {
+                /* The Listener line has a port */
+                port_matches = (port == conn->port);
+              } else if (port_option == CFG_AUTO_PORT) {
+                /* The Listener line has no port, and the Port line is "auto".
+                 * "auto" matches anything; transitions from any port to
+                 * "auto" succeed. */
+                port_matches = 1;
+              } else {
+                /*  The Listener line has no port, and the Port line is "auto".
+                 * "auto" matches anything; transitions from any port to
+                 * "auto" succeed. */
+                port_matches = (port_option == conn->port);
+              }
+              if (port_matches  && addr_matches) {
                 line = wanted;
                 line = wanted;
                 break;
                 break;
               }
               }
@@ -1860,7 +1895,7 @@ retry_listeners(int type, config_line_t *cfg,
           case AF_INET:
           case AF_INET:
             listensockaddr = (struct sockaddr *)
             listensockaddr = (struct sockaddr *)
                              create_inet_sockaddr(cfg_line->value,
                              create_inet_sockaddr(cfg_line->value,
-                                                  (uint16_t) port_option,
+                                                  port_option,
                                                   &address, &listensocklen);
                                                   &address, &listensocklen);
             break;
             break;
           case AF_UNIX:
           case AF_UNIX:

+ 105 - 0
src/or/control.c

@@ -515,6 +515,53 @@ connection_printf_to_buf(control_connection_t *conn, const char *format, ...)
   connection_write_to_buf(buf, len, TO_CONN(conn));
   connection_write_to_buf(buf, len, TO_CONN(conn));
 }
 }
 
 
+/** Write all of the open control ports to ControlPortWriteToFile */
+void
+control_ports_write_to_file(void)
+{
+  smartlist_t *lines;
+  char *joined = NULL;
+  or_options_t *options = get_options();
+
+  if (!options->ControlPortWriteToFile)
+    return;
+
+  lines = smartlist_create();
+
+  SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) {
+    char *port_str = NULL;
+    if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close)
+      continue;
+#ifdef AF_UNIX
+    if (conn->socket_family == AF_UNIX) {
+      tor_asprintf(&port_str, "UNIX_PORT=%s\n", conn->address);
+      smartlist_add(lines, port_str);
+      continue;
+    }
+#endif
+    tor_asprintf(&port_str, "PORT=%s:%d\n", conn->address, conn->port);
+    smartlist_add(lines, port_str);
+  } SMARTLIST_FOREACH_END(conn);
+
+  joined = smartlist_join_strings(lines, "", 0, NULL);
+
+  if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) {
+    log_warn(LD_CONTROL, "Writing %s failed: %s",
+             options->ControlPortWriteToFile, strerror(errno));
+  }
+#ifndef MS_WINDOWS
+  if (options->ControlPortFileGroupReadable) {
+    if (chmod(options->ControlPortWriteToFile, 0640)) {
+      log_warn(LD_FS,"Unable to make %s group-readable.",
+               options->ControlPortWriteToFile);
+    }
+  }
+#endif
+  tor_free(joined);
+  SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
+  smartlist_free(lines);
+}
+
 /** Send a "DONE" message down the control connection <b>conn</b>. */
 /** Send a "DONE" message down the control connection <b>conn</b>. */
 static void
 static void
 send_control_done(control_connection_t *conn)
 send_control_done(control_connection_t *conn)
@@ -1472,6 +1519,63 @@ munge_extrainfo_into_routerinfo(const char *ri_body,
   return tor_strndup(ri_body, ri->signed_descriptor_len);
   return tor_strndup(ri_body, ri->signed_descriptor_len);
 }
 }
 
 
+/** Implementation helper for GETINFO: answers requests for information about
+ * which ports are bound. */
+static int
+getinfo_helper_listeners(control_connection_t *control_conn,
+                         const char *question,
+                         char **answer, const char **errmsg)
+{
+  int type;
+  smartlist_t *res;
+
+  (void)control_conn;
+  (void)errmsg;
+
+  if (!strcmp(question, "net/listeners/or"))
+    type = CONN_TYPE_OR_LISTENER;
+  else if (!strcmp(question, "net/listeners/dir"))
+    type = CONN_TYPE_DIR_LISTENER;
+  else if (!strcmp(question, "net/listeners/socks"))
+    type = CONN_TYPE_AP_LISTENER;
+  else if (!strcmp(question, "net/listeners/trans"))
+    type = CONN_TYPE_AP_TRANS_LISTENER;
+  else if (!strcmp(question, "net/listeners/natd"))
+    type = CONN_TYPE_AP_NATD_LISTENER;
+  else if (!strcmp(question, "net/listeners/dns"))
+    type = CONN_TYPE_AP_DNS_LISTENER;
+  else if (!strcmp(question, "net/listeners/control"))
+    type = CONN_TYPE_CONTROL_LISTENER;
+  else
+    return 0; /* unknown key */
+
+  res = smartlist_create();
+  SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
+    char *addr;
+    struct sockaddr_storage ss;
+    socklen_t ss_len = sizeof(ss);
+
+    if (conn->type != type || conn->marked_for_close || conn->s < 0)
+      continue;
+
+    if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) {
+      tor_asprintf(&addr, "%s:%d", conn->address, (int)conn->port);
+    } else {
+      char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss);
+      addr = esc_for_log(tmp);
+      tor_free(tmp);
+    }
+    if (addr)
+      smartlist_add(res, addr);
+  } SMARTLIST_FOREACH_END(conn);
+
+  *answer = smartlist_join_strings(res, " ", 0, NULL);
+
+  SMARTLIST_FOREACH(res, char *, cp, tor_free(cp));
+  smartlist_free(res);
+  return 0;
+}
+
 /** Implementation helper for GETINFO: knows the answers for questions about
 /** Implementation helper for GETINFO: knows the answers for questions about
  * directory information. */
  * directory information. */
 static int
 static int
@@ -1927,6 +2031,7 @@ static const getinfo_item_t getinfo_items[] = {
        "All non-expired, non-superseded router descriptors."),
        "All non-expired, non-superseded router descriptors."),
   ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */
   ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */
   PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."),
   PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."),
+  PREFIX("net/listeners/", listeners, "Bound addresses by type"),
   ITEM("ns/all", networkstatus,
   ITEM("ns/all", networkstatus,
        "Brief summary of router status (v2 directory format)"),
        "Brief summary of router status (v2 directory format)"),
   PREFIX("ns/id/", networkstatus,
   PREFIX("ns/id/", networkstatus,

+ 2 - 0
src/or/control.h

@@ -15,6 +15,8 @@
 void control_update_global_event_mask(void);
 void control_update_global_event_mask(void);
 void control_adjust_event_log_severity(void);
 void control_adjust_event_log_severity(void);
 
 
+void control_ports_write_to_file(void);
+
 /** Log information about the connection <b>conn</b>, protecting it as with
 /** Log information about the connection <b>conn</b>, protecting it as with
  * CONN_LOG_PROTECT. Example:
  * CONN_LOG_PROTECT. Example:
  *
  *

+ 4 - 3
src/or/dirserv.c

@@ -2726,8 +2726,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
   voter->sigs = smartlist_create();
   voter->sigs = smartlist_create();
   voter->address = hostname;
   voter->address = hostname;
   voter->addr = addr;
   voter->addr = addr;
-  voter->dir_port = options->DirPort;
-  voter->or_port = options->ORPort;
+  voter->dir_port = router_get_advertised_dir_port(options);
+  voter->or_port = router_get_advertised_or_port(options);
   voter->contact = tor_strdup(contact);
   voter->contact = tor_strdup(contact);
   if (options->V3AuthUseLegacyKey) {
   if (options->V3AuthUseLegacyKey) {
     authority_cert_t *c = get_my_v3_legacy_cert();
     authority_cert_t *c = get_my_v3_legacy_cert();
@@ -2829,7 +2829,8 @@ generate_v2_networkstatus_opinion(void)
                "dir-options%s%s%s%s\n"
                "dir-options%s%s%s%s\n"
                "%s" /* client version line, server version line. */
                "%s" /* client version line, server version line. */
                "dir-signing-key\n%s",
                "dir-signing-key\n%s",
-               hostname, fmt_addr32(addr), (int)options->DirPort,
+               hostname, fmt_addr32(addr),
+               (int)router_get_advertised_dir_port(options),
                fingerprint,
                fingerprint,
                contact,
                contact,
                published,
                published,

+ 4 - 2
src/or/main.c

@@ -2283,12 +2283,14 @@ void
 tor_cleanup(void)
 tor_cleanup(void)
 {
 {
   or_options_t *options = get_options();
   or_options_t *options = get_options();
-  /* Remove our pid file. We don't care if there was an error when we
-   * unlink, nothing we could do about it anyways. */
   if (options->command == CMD_RUN_TOR) {
   if (options->command == CMD_RUN_TOR) {
     time_t now = time(NULL);
     time_t now = time(NULL);
+    /* Remove our pid file. We don't care if there was an error when we
+     * unlink, nothing we could do about it anyways. */
     if (options->PidFile)
     if (options->PidFile)
       unlink(options->PidFile);
       unlink(options->PidFile);
+    if (options->ControlPortWriteToFile)
+      unlink(options->ControlPortWriteToFile);
     if (accounting_is_enabled(options))
     if (accounting_is_enabled(options))
       accounting_record_bandwidth_usage(now, get_or_state());
       accounting_record_bandwidth_usage(now, get_or_state());
     or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */
     or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */

+ 9 - 0
src/or/or.h

@@ -2518,6 +2518,10 @@ typedef struct config_line_t {
 
 
 typedef struct routerset_t routerset_t;
 typedef struct routerset_t routerset_t;
 
 
+/** A magic value for the (Socks|OR|...)Port options below, telling Tor
+ * to pick its own port. */
+#define CFG_AUTO_PORT 0xc4005e
+
 /** Configuration options for a Tor process. */
 /** Configuration options for a Tor process. */
 typedef struct {
 typedef struct {
   uint32_t _magic;
   uint32_t _magic;
@@ -3057,6 +3061,11 @@ typedef struct {
    * If -1, Tor decides. */
    * If -1, Tor decides. */
   int UseMicrodescriptors;
   int UseMicrodescriptors;
 
 
+  /** File where we should write the ControlPort. */
+  char *ControlPortWriteToFile;
+  /** Should that file be group-readable? */
+  int ControlPortFileGroupReadable;
+
 } or_options_t;
 } or_options_t;
 
 
 /** Persistent state for an onion router, as saved to disk. */
 /** Persistent state for an onion router, as saved to disk. */

+ 34 - 4
src/or/router.c

@@ -707,8 +707,8 @@ init_keys(void)
   ds = router_get_trusteddirserver_by_digest(digest);
   ds = router_get_trusteddirserver_by_digest(digest);
   if (!ds) {
   if (!ds) {
     ds = add_trusted_dir_server(options->Nickname, NULL,
     ds = add_trusted_dir_server(options->Nickname, NULL,
-                                (uint16_t)options->DirPort,
-                                (uint16_t)options->ORPort,
+                                router_get_advertised_dir_port(options),
+                                router_get_advertised_or_port(options),
                                 digest,
                                 digest,
                                 v3_digest,
                                 v3_digest,
                                 type);
                                 type);
@@ -1171,6 +1171,36 @@ consider_publishable_server(int force)
   }
   }
 }
 }
 
 
+/** Return the port that we should advertise as our ORPort; this is either
+ * the one configured in the ORPort option, or the one we actually bound to
+ * if ORPort is "auto". */
+uint16_t
+router_get_advertised_or_port(or_options_t *options)
+{
+  if (options->ORPort == CFG_AUTO_PORT) {
+    connection_t *c = connection_get_by_type(CONN_TYPE_OR_LISTENER);
+    if (c)
+      return c->port;
+    return 0;
+  }
+  return options->ORPort;
+}
+
+/** Return the port that we should advertise as our DirPort; this is either
+ * the one configured in the DirPort option, or the one we actually bound to
+ * if DirPort is "auto". */
+uint16_t
+router_get_advertised_dir_port(or_options_t *options)
+{
+  if (options->DirPort == CFG_AUTO_PORT) {
+    connection_t *c = connection_get_by_type(CONN_TYPE_DIR_LISTENER);
+    if (c)
+      return c->port;
+    return 0;
+  }
+  return options->DirPort;
+}
+
 /*
 /*
  * OR descriptor generation.
  * OR descriptor generation.
  */
  */
@@ -1400,8 +1430,8 @@ router_rebuild_descriptor(int force)
   ri->address = tor_dup_ip(addr);
   ri->address = tor_dup_ip(addr);
   ri->nickname = tor_strdup(options->Nickname);
   ri->nickname = tor_strdup(options->Nickname);
   ri->addr = addr;
   ri->addr = addr;
-  ri->or_port = options->ORPort;
-  ri->dir_port = options->DirPort;
+  ri->or_port = router_get_advertised_or_port(options);
+  ri->dir_port = router_get_advertised_dir_port(options);
   ri->cache_info.published_on = time(NULL);
   ri->cache_info.published_on = time(NULL);
   ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
   ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
                                                         * main thread */
                                                         * main thread */

+ 3 - 0
src/or/router.h

@@ -50,6 +50,9 @@ int authdir_mode_publishes_statuses(or_options_t *options);
 int authdir_mode_tests_reachability(or_options_t *options);
 int authdir_mode_tests_reachability(or_options_t *options);
 int authdir_mode_bridge(or_options_t *options);
 int authdir_mode_bridge(or_options_t *options);
 
 
+uint16_t router_get_advertised_or_port(or_options_t *options);
+uint16_t router_get_advertised_dir_port(or_options_t *options);
+
 int server_mode(or_options_t *options);
 int server_mode(or_options_t *options);
 int public_server_mode(or_options_t *options);
 int public_server_mode(or_options_t *options);
 int advertised_server_mode(void);
 int advertised_server_mode(void);