summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2006-07-17 06:35:06 +0000
committerRoger Dingledine <arma@torproject.org>2006-07-17 06:35:06 +0000
commitf53cbeeb68b97438145067ca418e1ab35d867471 (patch)
treeff097afa2b9d20601c357ffec475df49b87d1db6
parentaae02335aacca1419e79a306a3c725ce8bd0e689 (diff)
downloadtor-f53cbeeb68b97438145067ca418e1ab35d867471.tar.gz
tor-f53cbeeb68b97438145067ca418e1ab35d867471.zip
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
-rw-r--r--trunk/src/or/config.c2
-rw-r--r--trunk/src/or/directory.c27
-rw-r--r--trunk/src/or/or.h2
-rw-r--r--trunk/src/or/router.c98
4 files changed, 99 insertions, 30 deletions
diff --git a/trunk/src/or/config.c b/trunk/src/or/config.c
index 7148f40d4c..fcca7acf91 100644
--- a/trunk/src/or/config.c
+++ b/trunk/src/or/config.c
@@ -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)
diff --git a/trunk/src/or/directory.c b/trunk/src/or/directory.c
index dd920893eb..52ebf19f23 100644
--- a/trunk/src/or/directory.c
+++ b/trunk/src/or/directory.c
@@ -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) {
diff --git a/trunk/src/or/or.h b/trunk/src/or/or.h
index 9f3c96d18f..5700221fa1 100644
--- a/trunk/src/or/or.h
+++ b/trunk/src/or/or.h
@@ -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);
diff --git a/trunk/src/or/router.c b/trunk/src/or/router.c
index 9f7913cf65..0e577a8031 100644
--- a/trunk/src/or/router.c
+++ b/trunk/src/or/router.c
@@ -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,29 +935,62 @@ 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;
+ 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;
- in_prev.s_addr = htonl(prev);
- tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
+/** 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;
- in_cur.s_addr = htonl(cur);
- tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
+ /* 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);
- log_info(LD_GENERAL,
- "Our IP Address has changed from %s to %s; "
- "rebuilding descriptor.",
- addrbuf_prev, addrbuf_cur);
- mark_my_descriptor_dirty();
+ 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