Merge branch 'feature3076_squashed' into maint-0.2.2

This commit is contained in:
Nick Mathewson 2011-05-13 10:43:41 -04:00
commit 5f2a1a7b4f
13 changed files with 319 additions and 70 deletions

14
changes/feature3076 Normal file
View File

@ -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.

View File

@ -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)
@ -647,10 +659,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
@ -759,23 +772,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).
@ -791,9 +806,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).
@ -945,8 +961,10 @@ is non-zero):
**NumCPUs** __num__:: **NumCPUs** __num__::
How many processes to use at once for decrypting onionskins. (Default: 1) How many processes to use at once for decrypting onionskins. (Default: 1)
**ORPort** __PORT__:: **ORPort** __PORT__|**auto**::
Advertise this port to listen for connections from Tor clients and servers. 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
@ -1158,8 +1176,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__:: **DirPort** __PORT__|**auto**::
Advertise the directory service on this port. 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

View File

@ -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

View File

@ -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. */

View File

@ -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_MEMUNIT, /**< A number of bytes, with optional units*/ CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/
CONFIG_TYPE_DOUBLE, /**< A floating-point value */ CONFIG_TYPE_DOUBLE, /**< A floating-point value */
@ -203,7 +205,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"),
@ -215,7 +219,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"),
@ -225,7 +229,7 @@ static config_var_t _option_vars[] = {
V(DirReqStatistics, BOOL, "0"), V(DirReqStatistics, BOOL, "0"),
VAR("DirServer", LINELIST, DirServers, NULL), VAR("DirServer", LINELIST, DirServers, NULL),
V(DisableAllSwap, BOOL, "0"), V(DisableAllSwap, BOOL, "0"),
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"),
@ -304,7 +308,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"),
@ -312,7 +316,7 @@ static config_var_t _option_vars[] = {
V(NumCPUs, UINT, "1"), V(NumCPUs, UINT, "1"),
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"),
@ -355,7 +359,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"),
@ -366,7 +370,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"),
@ -561,7 +565,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);
@ -1689,8 +1693,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.",
@ -1998,6 +2010,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_UINT: case CONFIG_TYPE_UINT:
/* This means every or_options_t uint or bool element /* This means every or_options_t uint or bool element
@ -2227,6 +2245,7 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
break; break;
case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_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;
@ -2606,7 +2625,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
@ -2851,9 +2870,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") ||
@ -2968,18 +2984,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)
@ -2988,12 +2992,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.");
@ -5238,6 +5236,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_MEMUNIT: type = "DataSize"; break; case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
case CONFIG_TYPE_DOUBLE: type = "Float"; break; case CONFIG_TYPE_DOUBLE: type = "Float"; break;

View File

@ -37,7 +37,7 @@
#include "routerparse.h" #include "routerparse.h"
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,
@ -759,7 +759,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;
@ -771,8 +771,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) if (usePort==0) {
usePort = listenport; 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);
@ -858,12 +860,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) {
@ -872,6 +875,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;
@ -879,11 +883,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) tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
((struct sockaddr_in *)listensockaddr)->sin_port);
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,
@ -921,6 +924,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;
@ -968,7 +986,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.");
@ -976,8 +994,12 @@ connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
goto err; goto err;
} }
log_debug(LD_NET,"%s listening on port %u.", log_fn(usePort==gotPort ? LOG_DEBUG : LOG_NOTICE, LD_NET,
conn_type_to_string(type), usePort); "%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) {
@ -1753,10 +1775,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) if (port) {
port = port_option; /* The Listener line has a port */
if (port == conn->port && addr_matches) { 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;
} }
@ -1804,7 +1839,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:

View File

@ -508,6 +508,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)
@ -1407,6 +1454,63 @@ munge_extrainfo_into_routerinfo(const char *ri_body, signed_descriptor_t *ri,
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
@ -1861,6 +1965,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,

View File

@ -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:
* *

View File

@ -2699,8 +2699,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->dir_port = router_get_advertised_dir_port(options);
voter->or_port = options->ORPort; 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();
@ -2806,7 +2806,7 @@ 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, ipaddr, (int)options->DirPort, hostname, ipaddr, (int)router_get_advertised_dir_port(options),
fingerprint, fingerprint,
contact, contact,
published, published,

View File

@ -2046,12 +2046,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. */

View File

@ -2353,6 +2353,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;
@ -2870,6 +2874,11 @@ typedef struct {
* the defaults have changed. */ * the defaults have changed. */
int _UsingTestNetworkDefaults; int _UsingTestNetworkDefaults;
/** 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. */

View File

@ -704,8 +704,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, router_get_advertised_dir_port(options),
(uint16_t)options->ORPort, router_get_advertised_or_port(options),
digest, digest,
v3_digest, v3_digest,
type); type);
@ -1165,6 +1165,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.
*/ */
@ -1398,8 +1428,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->or_port = router_get_advertised_or_port(options);
ri->dir_port = options->DirPort; 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 */

View File

@ -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);