From 0a6e27208b53089d7f171fd131b3eb6cb3fd0901 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Mon, 16 Aug 2004 11:43:18 +0000 Subject: [PATCH] o Handle servers with dynamic IP addresses: don't replace options->Address with the resolved one at startup. o detect our address right before we make a routerinfo each time. o external IP vs bind-IP. Already done, just use options->Address. o OutboundBindAddress config option, to bind to a specific IP address for outgoing connect()s. svn:r2241 --- src/or/config.c | 54 +++++++++++++++++++++++++++------------------ src/or/connection.c | 19 ++++++++++++++++ src/or/or.h | 9 +++++--- src/or/router.c | 13 ++++++----- 4 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 067ab4ba64..8a28e02c62 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -213,6 +213,11 @@ static int config_assign(or_options_t *options, struct config_line_t *list) { config_compare(list, "Group", CONFIG_TYPE_STRING, &options->Group) || + config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| + config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| + config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| + config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| + config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) || config_compare(list, "KeepalivePeriod",CONFIG_TYPE_INT, &options->KeepalivePeriod) || @@ -230,12 +235,14 @@ static int config_assign(or_options_t *options, struct config_line_t *list) { config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) || config_compare(list, "ORBindAddress", CONFIG_TYPE_LINELIST, &options->ORBindAddress) || + config_compare(list, "OutboundBindAddress",CONFIG_TYPE_STRING, &options->OutboundBindAddress) || config_compare(list, "PidFile", CONFIG_TYPE_STRING, &options->PidFile) || config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) || config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) || config_compare(list, "RunAsDaemon", CONFIG_TYPE_BOOL, &options->RunAsDaemon) || + config_compare(list, "RunTesting", CONFIG_TYPE_BOOL, &options->RunTesting) || config_compare(list, "RecommendedVersions",CONFIG_TYPE_STRING, &options->RecommendedVersions) || config_compare(list, "RendNodes", CONFIG_TYPE_STRING, &options->RendNodes) || config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) || @@ -246,12 +253,9 @@ static int config_assign(or_options_t *options, struct config_line_t *list) { config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) || - config_compare(list, "User", CONFIG_TYPE_STRING, &options->User) || - config_compare(list, "RunTesting", CONFIG_TYPE_BOOL, &options->RunTesting) || - config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| - config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| - config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)|| - config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines) + config_compare(list, "User", CONFIG_TYPE_STRING, &options->User) + + ) { /* then we're ok. it matched something. */ } else { @@ -422,31 +426,34 @@ static void print_usage(void) { /** * Adjust options to contain a reasonable value for Address. */ -static int resolve_my_address(or_options_t *options) { +int resolve_my_address(const char *address, uint32_t *addr) { struct in_addr in; struct hostent *rent; - char localhostname[256]; + char hostname[256]; int explicit_ip=1; - if(!options->Address) { /* then we need to guess our address */ + tor_assert(addr); + + if(address) { + strlcpy(hostname,address,sizeof(hostname)); + } else { /* then we need to guess our address */ explicit_ip = 0; /* it's implicit */ - if(gethostname(localhostname,sizeof(localhostname)) < 0) { + if(gethostname(hostname,sizeof(hostname)) < 0) { log_fn(LOG_WARN,"Error obtaining local hostname"); return -1; } - options->Address = tor_strdup(localhostname); - log_fn(LOG_DEBUG,"Guessed local host name as '%s'",options->Address); + log_fn(LOG_DEBUG,"Guessed local host name as '%s'",hostname); } - /* now we know options->Address is set. resolve it and keep only the IP */ + /* now we know hostname. resolve it and keep only the IP */ - if(tor_inet_aton(options->Address, &in) == 0) { + if(tor_inet_aton(hostname, &in) == 0) { /* then we have to resolve it */ explicit_ip = 0; - rent = (struct hostent *)gethostbyname(options->Address); + rent = (struct hostent *)gethostbyname(hostname); if (!rent) { - log_fn(LOG_WARN,"Could not resolve Address %s. Failing.", options->Address); + log_fn(LOG_WARN,"Could not resolve local Address %s. Failing.", hostname); return -1; } tor_assert(rent->h_length == 4); @@ -455,12 +462,11 @@ static int resolve_my_address(or_options_t *options) { if(!explicit_ip && is_internal_IP(htonl(in.s_addr))) { log_fn(LOG_WARN,"Address '%s' resolves to private IP '%s'. " "Please set the Address config option to be the IP you want to use.", - options->Address, inet_ntoa(in)); + hostname, inet_ntoa(in)); return -1; } - tor_free(options->Address); - options->Address = tor_strdup(inet_ntoa(in)); - log_fn(LOG_DEBUG,"Resolved Address to %s.", options->Address); + log_fn(LOG_DEBUG,"Resolved Address to %s.", inet_ntoa(in)); + *addr = ntohl(in.s_addr); return 0; } @@ -513,6 +519,7 @@ static void free_options(or_options_t *options) { tor_free(options->ExcludeNodes); tor_free(options->RendNodes); tor_free(options->RendExcludeNodes); + tor_free(options->OutboundBindAddress); tor_free(options->RecommendedVersions); tor_free(options->User); tor_free(options->Group); @@ -540,6 +547,7 @@ static void init_options(or_options_t *options) { options->SocksBindAddress = NULL; options->ORBindAddress = NULL; options->DirBindAddress = NULL; + options->OutboundBindAddress = NULL; options->RecommendedVersions = NULL; options->PidFile = NULL; // tor_strdup("tor.pid"); options->DataDirectory = NULL; @@ -696,8 +704,10 @@ int getconfig(int argc, char **argv, or_options_t *options) { } } - if(server_mode()) { /* get an IP for ourselves */ - if(resolve_my_address(options) < 0) + if(server_mode()) { + /* confirm that our address isn't broken, so we can complain now */ + uint32_t tmp; + if(resolve_my_address(options->Address, &tmp) < 0) result = -1; } diff --git a/src/or/connection.c b/src/or/connection.c index f37cae100a..74da0d6d07 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -482,6 +482,25 @@ int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_ tor_socket_strerror(tor_socket_errno(-1))); return -1; } + + if (options.OutboundBindAddress) { + struct sockaddr_in ext_addr; + + memset(&ext_addr, 0, sizeof(ext_addr)); + ext_addr.sin_family = AF_INET; + ext_addr.sin_port = 0; + if (!tor_inet_aton(options.OutboundBindAddress, &ext_addr.sin_addr)) { + log_fn(LOG_WARN,"Outbound bind address '%s' didn't parse. Ignoring.", + options.OutboundBindAddress); + } else { + if(bind(s, (struct sockaddr*)&ext_addr, sizeof(ext_addr) < 0)) { + log_fn(LOG_WARN,"Error binding network socket: %s", + tor_socket_strerror(tor_socket_errno(s))); + return -1; + } + } + } + set_socket_nonblocking(s); memset(&dest_addr,0,sizeof(dest_addr)); diff --git a/src/or/or.h b/src/or/or.h index a382e9b32e..9d3fd976cb 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -838,12 +838,14 @@ typedef struct { struct config_line_t *ExitPolicy; /**< Lists of exit policy components. */ struct config_line_t *SocksPolicy; /**< Lists of socks policy components */ + /** Addresses to bind for listening for SOCKS connections. */ struct config_line_t *SocksBindAddress; - /**< Addresses to bind for listening for SOCKS connections. */ + /** Addresses to bind for listening for OR connections. */ struct config_line_t *ORBindAddress; - /**< Addresses to bind for listening for OR connections. */ + /** Addresses to bind for listening for directory connections. */ struct config_line_t *DirBindAddress; - /**< Addresses to bind for listening for directory connections. */ + /** Local address to bind outbound sockets */ + char *OutboundBindAddress; char *RecommendedVersions; /**< Directory server only: which versions of * Tor should we tell users to run? */ char *User; /**< Name of user to run Tor as. */ @@ -1021,6 +1023,7 @@ struct config_line_t { }; int config_assign_default_dirservers(void); +int resolve_my_address(const char *address, uint32_t *addr); int getconfig(int argc, char **argv, or_options_t *options); int config_init_logs(or_options_t *options); void config_parse_exit_policy(struct config_line_t *cfg, diff --git a/src/or/router.c b/src/or/router.c index 972b8f8f19..440e404282 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -510,17 +510,20 @@ const char *router_get_my_descriptor(void) { */ int router_rebuild_descriptor(void) { routerinfo_t *ri; - struct in_addr addr; + uint32_t addr; char platform[256]; - if (!tor_inet_aton(options.Address, &addr)) { - log_fn(LOG_ERR, "options.Address didn't hold an IP."); + struct in_addr in; + + if(resolve_my_address(options.Address, &addr) < 0) { + log_fn(LOG_WARN,"options.Address didn't resolve into an IP."); return -1; } ri = tor_malloc_zero(sizeof(routerinfo_t)); - ri->address = tor_strdup(options.Address); + in.s_addr = htonl(addr); + ri->address = tor_strdup(inet_ntoa(in)); ri->nickname = tor_strdup(options.Nickname); - ri->addr = (uint32_t) ntohl(addr.s_addr); + ri->addr = addr; ri->or_port = options.ORPort; ri->socks_port = options.SocksPort; ri->dir_port = options.DirPort;