diff --git a/ChangeLog b/ChangeLog
index 8d939557e7..a51a3e35f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -51,6 +51,9 @@ Changes in version 0.1.2.2-alpha - 2006-10-??
available in non-Exit nodes is much higher then the bandwidth available
in Exit nodes. (Fixes bug 200.)
- Give more meaningful errors on control authentication failure.
+ - When deciding whether an IP is "local", check for IPs on the same /24
+ as us. This prevents some false positives during reachability
+ detection.
o Security Fixes, minor:
- If a client asked for a server by name, and we didn't have a
diff --git a/src/common/util.c b/src/common/util.c
index f7d27bb20a..7e4a35deb0 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1572,17 +1572,6 @@ is_internal_IP(uint32_t ip, int for_listening)
return 0;
}
-/** Return true iff ip (in host order) is judged to be on the
- * same network as us. For now, check if it's an internal IP.
- *
- * XXX Also check if it's on the same class C network as our public IP.
- */
-int
-is_local_IP(uint32_t ip)
-{
- return is_internal_IP(ip, 0);
-}
-
/** Parse a string of the form "host[:port]" from addrport. If
* address is provided, set *address to a copy of the
* host portion of the string. If addr is provided, try to
diff --git a/src/common/util.h b/src/common/util.h
index b09b90cd10..082e9db51a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -188,7 +188,6 @@ int path_is_relative(const char *filename) ATTR_PURE;
/* Net helpers */
int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE;
-int is_local_IP(uint32_t ip) ATTR_PURE;
int parse_addr_port(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out);
int parse_port_range(const char *port, uint16_t *port_min_out,
diff --git a/src/or/config.c b/src/or/config.c
index 8407367ee1..5899f2b6a2 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1590,6 +1590,8 @@ print_usage(void)
"See man page for options, or http://tor.eff.org/ for documentation.\n");
}
+/** Last value actually set by resolve_my_address. */
+static uint32_t last_resolved_addr = 0;
/**
* Based on options-\>Address, guess our public IP address and put it
* (in host order) into *addr_out. If hostname_out is provided,
@@ -1607,7 +1609,6 @@ resolve_my_address(int warn_severity, or_options_t *options,
int explicit_ip=1;
int explicit_hostname=1;
char tmpbuf[INET_NTOA_BUF_LEN];
- static uint32_t old_addr=0;
const char *address = options->Address;
int notice_severity = warn_severity <= LOG_NOTICE ?
LOG_NOTICE : warn_severity;
@@ -1714,18 +1715,41 @@ resolve_my_address(int warn_severity, or_options_t *options,
log_debug(LD_CONFIG, "Resolved Address to '%s'.", tmpbuf);
*addr_out = ntohl(in.s_addr);
- if (old_addr && old_addr != *addr_out) {
+ if (last_resolved_addr && last_resolved_addr != *addr_out) {
/* Leave this as a notice, regardless of the requested severity,
* at least until dynamic IP address support becomes bulletproof. */
log_notice(LD_NET, "Your IP address seems to have changed. Updating.");
server_has_changed_ip();
}
- old_addr = *addr_out;
+ last_resolved_addr = *addr_out;
if (hostname_out)
*hostname_out = tor_strdup(hostname);
return 0;
}
+/** Return true iff ip (in host order) is judged to be on the
+ * same network as us, or on a private network.
+ */
+int
+is_local_IP(uint32_t ip)
+{
+ if (is_internal_IP(ip, 0))
+ return 1;
+ /* Check whether ip is on the same /24 as we are.
+ *
+ * It's possible that this next check will hit before the first time
+ * resolve_my_address actually succeeds. (For clients, it is likely that
+ * resolve_my_address will never be called at all). In those cases,
+ * last_resolved_addr will be 0, and so checking to see whether ip is on the
+ * same /24 as last_resolved_addr will be the same as checking whether it
+ * was on net 0, which is already done by is_internal_IP.
+ */
+ if ((last_resolved_addr & 0xffffff00ul) == (ip & 0xffffff00ul))
+ return 1;
+ return 0;
+}
+
+
/** Called when we don't have a nickname set. Try to guess a good nickname
* based on the hostname, and return it in a newly allocated string. If we
* can't, return NULL and let the caller warn if it wants to. */
diff --git a/src/or/connection.c b/src/or/connection.c
index 9c64e324f4..3450bf184f 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1425,7 +1425,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
*max_to_read = at_most - result;
}
- if (result > 0 && !is_local_IP(conn->addr)) { /* remember it */
+ if (result > 0 && !is_internal_IP(conn->addr, 0)) { /* remember it */
rep_hist_note_bytes_read(result, time(NULL));
connection_read_bucket_decrement(conn, result);
}
@@ -1601,7 +1601,7 @@ connection_handle_write(connection_t *conn)
}
if (result > 0) {
- if (!is_local_IP(conn->addr)) { /* remember it */
+ if (!is_internal_IP(conn->addr, 0)) { /* remember it */
rep_hist_note_bytes_written(result, time(NULL));
global_write_bucket -= result;
}
@@ -1646,7 +1646,7 @@ _connection_controller_force_write(control_connection_t *control_conn)
}
if (result > 0) {
- if (!is_local_IP(conn->addr)) { /* remember it */
+ if (!is_internal_IP(conn->addr, 0)) { /* remember it */
rep_hist_note_bytes_written(result, time(NULL));
global_write_bucket -= result;
}
diff --git a/src/or/or.h b/src/or/or.h
index a73b284bd9..beed25e9e8 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1821,6 +1821,7 @@ int options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
int resolve_my_address(int warn_severity, or_options_t *options,
uint32_t *addr, char **hostname_out);
+int is_local_IP(uint32_t ip) ATTR_PURE;
void options_init(or_options_t *options);
int options_init_from_torrc(int argc, char **argv);
int options_init_logs(or_options_t *options, int validate_only);