mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Allow servers with no hostname or IP address to learn their IP address
by asking the directory authorities. This code only kicks in when you would normally have exited with a "no address" error. This design is flawed, though, since the X-Your-Address-Is header is not authenticated, and doing it this way introduces too many new attacks. The right answer is to give IP address hints inside the HELLO cell; much of this code can be reused when we switch. svn:r6774
This commit is contained in:
+1
-1
@@ -2129,7 +2129,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
options->PublishServerDescriptor = 0;
|
||||
}
|
||||
|
||||
if (server_mode(options)) {
|
||||
if (authdir_mode(options)) {
|
||||
/* confirm that our address isn't broken, so we can complain now */
|
||||
uint32_t tmp;
|
||||
if (resolve_my_address(LOG_WARN, options, &tmp, NULL) < 0)
|
||||
|
||||
+17
-10
@@ -58,6 +58,8 @@ static void note_request(const char *key, size_t bytes);
|
||||
* before deciding that one of us has the wrong time? */
|
||||
#define ALLOW_DIRECTORY_TIME_SKEW (30*60)
|
||||
|
||||
#define X_ADDRESS_HEADER "X-Your-Address-Is: "
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
/** Return true iff the directory purpose 'purpose' must use an
|
||||
@@ -386,6 +388,7 @@ directory_initiate_command(const char *address, uint32_t addr,
|
||||
|
||||
/* give it an initial state */
|
||||
conn->state = DIR_CONN_STATE_CONNECTING;
|
||||
conn->dirconn_direct = (private_connection == 0);
|
||||
|
||||
if (!private_connection) {
|
||||
/* then we want to connect directly */
|
||||
@@ -658,9 +661,8 @@ http_get_header(const char *headers, const char *which)
|
||||
}
|
||||
|
||||
/** If <b>headers</b> indicates that a proxy was involved, then rewrite
|
||||
* <b>conn</b>-\>address to describe our best guess of the addresses
|
||||
* involved in this HTTP request. The format is either "1.2.3.4" or
|
||||
* "1.2.3.4 (forwarded for 5.6.7.8)". */
|
||||
* <b>conn</b>-\>address to describe our best guess of the address that
|
||||
* originated this HTTP request. */
|
||||
static void
|
||||
http_set_address_origin(const char *headers, connection_t *conn)
|
||||
{
|
||||
@@ -670,13 +672,9 @@ http_set_address_origin(const char *headers, connection_t *conn)
|
||||
if (!fwd)
|
||||
fwd = http_get_header(headers, "X-Forwarded-For: ");
|
||||
if (fwd) {
|
||||
size_t len = strlen(fwd)+strlen(conn->address)+32;
|
||||
char *result = tor_malloc(len);
|
||||
tor_snprintf(result, len, "%s (forwarded for %s)", conn->address,
|
||||
escaped(fwd));
|
||||
tor_free(fwd);
|
||||
tor_free(conn->address);
|
||||
conn->address = result;
|
||||
conn->address = tor_strdup(escaped(fwd));
|
||||
tor_free(fwd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,6 +849,15 @@ connection_dir_client_reached_eof(connection_t *conn)
|
||||
"Received response from directory server '%s:%d': %d %s",
|
||||
conn->address, conn->port, status_code, escaped(reason));
|
||||
|
||||
/* now check if it's got any hints for us about our IP address. */
|
||||
if (server_mode(get_options())) {
|
||||
char *guess = http_get_header(headers, X_ADDRESS_HEADER);
|
||||
if (guess) {
|
||||
router_new_address_suggestion(guess);
|
||||
tor_free(guess);
|
||||
}
|
||||
}
|
||||
|
||||
if (date_header > 0) {
|
||||
now = time(NULL);
|
||||
delta = now-date_header;
|
||||
@@ -1264,7 +1271,7 @@ write_http_response_header(connection_t *conn, ssize_t length,
|
||||
cp = tmp;
|
||||
tor_snprintf(cp, sizeof(tmp),
|
||||
"HTTP/1.0 200 OK\r\nDate: %s\r\nContent-Type: %s\r\n"
|
||||
"X-Your-Address-Is: %s\r\n",
|
||||
X_ADDRESS_HEADER "%s\r\n",
|
||||
date, type, conn->address);
|
||||
cp += strlen(tmp);
|
||||
if (encoding) {
|
||||
|
||||
@@ -691,6 +691,7 @@ struct connection_t {
|
||||
/* Used only by Dir connections */
|
||||
char *requested_resource; /**< Which 'resource' did we ask the directory
|
||||
* for? */
|
||||
unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */
|
||||
/* Used only for server sides of some dir connections. */
|
||||
enum {
|
||||
DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP,
|
||||
@@ -2274,6 +2275,7 @@ void mark_my_descriptor_dirty_if_older_than(time_t when);
|
||||
void mark_my_descriptor_dirty(void);
|
||||
void check_descriptor_bandwidth_changed(time_t now);
|
||||
void check_descriptor_ipaddress_changed(time_t now);
|
||||
void router_new_address_suggestion(const char *suggestion);
|
||||
int router_compare_to_my_exit_policy(connection_t *conn);
|
||||
routerinfo_t *router_get_my_routerinfo(void);
|
||||
const char *router_get_my_descriptor(void);
|
||||
|
||||
+81
-21
@@ -736,9 +736,11 @@ router_get_my_descriptor(void)
|
||||
/*DOCDOC*/
|
||||
static smartlist_t *warned_nonexistent_family = NULL;
|
||||
|
||||
static int router_guess_address_from_dir_headers(uint32_t *guess);
|
||||
|
||||
/** If <b>force</b> is true, or our descriptor is out-of-date, rebuild
|
||||
* a fresh routerinfo and signed server descriptor for this OR.
|
||||
* Return 0 on success, -1 on error.
|
||||
* Return 0 on success, -1 on temporary error.
|
||||
*/
|
||||
int
|
||||
router_rebuild_descriptor(int force)
|
||||
@@ -752,9 +754,14 @@ router_rebuild_descriptor(int force)
|
||||
if (desc_clean_since && !force)
|
||||
return 0;
|
||||
|
||||
if (resolve_my_address(LOG_WARN, options, &addr, NULL) < 0) {
|
||||
log_warn(LD_CONFIG,"options->Address didn't resolve into an IP.");
|
||||
return -1;
|
||||
if (resolve_my_address(LOG_INFO, options, &addr, NULL) < 0) {
|
||||
log_info(LD_CONFIG, "Could not determine our address locally. "
|
||||
"Checking if directory headers provide any hints.");
|
||||
if (router_guess_address_from_dir_headers(&addr) < 0) {
|
||||
log_info(LD_CONFIG, "No hints from directory headers either. "
|
||||
"Will try again later.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ri = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
@@ -894,6 +901,26 @@ check_descriptor_bandwidth_changed(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
log_addr_has_changed(uint32_t prev, uint32_t cur)
|
||||
{
|
||||
char addrbuf_prev[INET_NTOA_BUF_LEN];
|
||||
char addrbuf_cur[INET_NTOA_BUF_LEN];
|
||||
struct in_addr in_prev;
|
||||
struct in_addr in_cur;
|
||||
|
||||
in_prev.s_addr = htonl(prev);
|
||||
tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
|
||||
|
||||
in_cur.s_addr = htonl(cur);
|
||||
tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
|
||||
|
||||
log_info(LD_GENERAL,
|
||||
"Our IP Address has changed from %s to %s; "
|
||||
"rebuilding descriptor.",
|
||||
addrbuf_prev, addrbuf_cur);
|
||||
}
|
||||
|
||||
/** Check whether our own address as defined by the Address configuration
|
||||
* has changed. This is for routers that get their address from a service
|
||||
* like dyndns. If our address has changed, mark our descriptor dirty. */
|
||||
@@ -908,31 +935,64 @@ check_descriptor_ipaddress_changed(time_t now)
|
||||
return;
|
||||
|
||||
prev = desc_routerinfo->addr;
|
||||
if (resolve_my_address(LOG_WARN, options, &cur, NULL) < 0) {
|
||||
log_warn(LD_CONFIG,"options->Address didn't resolve into an IP.");
|
||||
if (resolve_my_address(LOG_INFO, options, &cur, NULL) < 0) {
|
||||
log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (prev != cur) {
|
||||
char addrbuf_prev[INET_NTOA_BUF_LEN];
|
||||
char addrbuf_cur[INET_NTOA_BUF_LEN];
|
||||
struct in_addr in_prev;
|
||||
struct in_addr in_cur;
|
||||
|
||||
in_prev.s_addr = htonl(prev);
|
||||
tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
|
||||
|
||||
in_cur.s_addr = htonl(cur);
|
||||
tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
|
||||
|
||||
log_info(LD_GENERAL,
|
||||
"Our IP Address has changed from %s to %s; "
|
||||
"rebuilding descriptor.",
|
||||
addrbuf_prev, addrbuf_cur);
|
||||
log_addr_has_changed(prev, cur);
|
||||
mark_my_descriptor_dirty();
|
||||
/* the above call is probably redundant, since resolve_my_address()
|
||||
* probably already noticed and marked it dirty. */
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t last_guessed_ip = 0;
|
||||
|
||||
/** A directory authority told us our IP address is <b>suggestion</b>.
|
||||
* If this address is different from the one we think we are now, and
|
||||
* if our computer doesn't actually know its IP address, then switch. */
|
||||
void
|
||||
router_new_address_suggestion(const char *suggestion)
|
||||
{
|
||||
uint32_t addr, cur;
|
||||
struct in_addr in;
|
||||
|
||||
/* first, learn what the IP address actually is */
|
||||
if (!tor_inet_aton(suggestion, &in)) {
|
||||
log_debug(LD_DIR, "Malformed X-Your-Address-Is header. Ignoring.");
|
||||
return;
|
||||
}
|
||||
addr = ntohl(in.s_addr);
|
||||
|
||||
if (resolve_my_address(LOG_INFO, get_options(), &cur, NULL) >= 0) {
|
||||
/* We're all set -- we already know our address. Great. */
|
||||
last_guessed_ip = cur; /* store it in case we need it later */
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_guessed_ip != addr) {
|
||||
log_addr_has_changed(last_guessed_ip, addr);
|
||||
server_has_changed_ip();
|
||||
last_guessed_ip = addr; /* router_rebuild_descriptor() will fetch it */
|
||||
}
|
||||
}
|
||||
|
||||
/** We failed to resolve our address locally, but we'd like to build
|
||||
* a descriptor and publish / test reachability. If we have a guess
|
||||
* about our address based on directory headers, answer it and return
|
||||
* 0; else return -1. */
|
||||
static int
|
||||
router_guess_address_from_dir_headers(uint32_t *guess)
|
||||
{
|
||||
if (last_guessed_ip) {
|
||||
*guess = last_guessed_ip;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
|
||||
* string describing the version of Tor and the operating system we're
|
||||
* currently running on.
|
||||
|
||||
Reference in New Issue
Block a user