summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address.c206
-rw-r--r--src/common/aes.c6
-rw-r--r--src/common/compat.c36
-rw-r--r--src/common/compat.h5
-rw-r--r--src/or/circuitlist.c75
-rw-r--r--src/or/circuitlist.h1
-rw-r--r--src/or/config.c12
-rw-r--r--src/or/connection.c44
-rw-r--r--src/or/control.c142
-rw-r--r--src/or/dirserv.c23
-rw-r--r--src/or/relay.c33
-rw-r--r--src/test/test_addr.c11
12 files changed, 502 insertions, 92 deletions
diff --git a/src/common/address.c b/src/common/address.c
index c53368743f..2e9892c4dc 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -13,10 +13,16 @@
#include "util.h"
#include "address.h"
#include "torlog.h"
+#include "container.h"
#ifdef MS_WINDOWS
#include <process.h>
#include <windows.h>
+#include <winsock2.h>
+/* For access to structs needed by GetAdaptersAddresses */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <iphlpapi.h>
#endif
#ifdef HAVE_SYS_TIME_H
@@ -46,6 +52,15 @@
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1086,6 +1101,169 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
return -1;
}
+#ifdef MS_WINDOWS
+typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
+ ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
+#endif
+
+/** Try to ask our network interfaces what addresses they are bound to.
+ * Return a new smartlist of tor_addr_t on success, and NULL on failure.
+ * (An empty smartlist indicates that we successfully learned that we have no
+ * addresses.) Log failure messages at <b>severity</b>. */
+static smartlist_t *
+get_interface_addresses_raw(int severity)
+{
+#if defined(HAVE_GETIFADDRS)
+ /* Most free Unixy systems provide getifaddrs, which gives us a linked list
+ * of struct ifaddrs. */
+ struct ifaddrs *ifa = NULL;
+ const struct ifaddrs *i;
+ smartlist_t *result;
+ if (getifaddrs(&ifa) < 0) {
+ log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ result = smartlist_create();
+ for (i = ifa; i; i = i->ifa_next) {
+ tor_addr_t tmp;
+ if (!i->ifa_addr)
+ continue;
+ if (i->ifa_addr->sa_family != AF_INET &&
+ i->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+
+ freeifaddrs(ifa);
+ return result;
+#elif defined(MS_WINDOWS)
+ /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
+ "GetAdaptersInfo", but that's deprecated; let's just try
+ GetAdaptersAddresses and fall back to connect+getsockname.
+ */
+ HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll"));
+ smartlist_t *result = NULL;
+ GetAdaptersAddresses_fn_t fn;
+ ULONG size, res;
+ IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
+
+ (void) severity;
+
+#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
+ GAA_FLAG_SKIP_MULTICAST | \
+ GAA_FLAG_SKIP_DNS_SERVER)
+
+ if (!lib) {
+ log_fn(severity, LD_NET, "Unable to load iphlpapi.dll");
+ goto done;
+ }
+
+ if (!(fn = (GetAdaptersAddresses_fn_t)
+ GetProcAddress(lib, "GetAdaptersAddresses"))) {
+ log_fn(severity, LD_NET, "Unable to obtain pointer to "
+ "GetAdaptersAddresses");
+ goto done;
+ }
+
+ /* Guess how much space we need. */
+ size = 15*1024;
+ addresses = tor_malloc(size);
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ if (res == ERROR_BUFFER_OVERFLOW) {
+ /* we didn't guess that we needed enough space; try again */
+ tor_free(addresses);
+ addresses = tor_malloc(size);
+ res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
+ }
+ if (res != NO_ERROR) {
+ log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res);
+ goto done;
+ }
+
+ result = smartlist_create();
+ for (address = addresses; address; address = address->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS *a;
+ for (a = address->FirstUnicastAddress; a; a = a->Next) {
+ /* Yes, it's a linked list inside a linked list */
+ struct sockaddr *sa = a->Address.lpSockaddr;
+ tor_addr_t tmp;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ continue;
+ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+ }
+
+ done:
+ if (lib)
+ FreeLibrary(lib);
+ tor_free(addresses);
+ return result;
+#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+ /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
+ struct ifconf ifc;
+ int fd, i, sz, n;
+ smartlist_t *result = NULL;
+ /* This interface, AFAICT, only supports AF_INET addresses */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ log(severity, LD_NET, "socket failed: %s", strerror(errno));
+ goto done;
+ }
+ /* Guess how much space we need. */
+ ifc.ifc_len = sz = 15*1024;
+ ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
+ close(fd);
+ goto done;
+ }
+ close(fd);
+ result = smartlist_create();
+ if (ifc.ifc_len < sz)
+ sz = ifc.ifc_len;
+ n = sz / sizeof(struct ifreq);
+ for (i = 0; i < n ; ++i) {
+ struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i];
+ struct sockaddr *sa = &r->ifr_addr;
+ tor_addr_t tmp;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ continue; /* should be impossible */
+ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+ done:
+ tor_free(ifc.ifc_ifcu.ifcu_req);
+ return result;
+#else
+ (void) severity;
+ return NULL;
+#endif
+}
+
+/** Return true iff <b>a</b> is a multicast address. */
+static int
+tor_addr_is_multicast(const tor_addr_t *a)
+{
+ sa_family_t family = tor_addr_family(a);
+ if (family == AF_INET) {
+ uint32_t ipv4h = tor_addr_to_ipv4h(a);
+ if ((ipv4h >> 24) == 0xe0)
+ return 1; /* Multicast */
+ } else if (family == AF_INET6) {
+ const uint8_t *a32 = tor_addr_to_in6_addr8(a);
+ if (a32[0] == 0xff)
+ return 1;
+ }
+ return 0;
+}
+
/** Set *<b>addr</b> to the IP address (if any) of whatever interface
* connects to the Internet. This address should only be used in checking
* whether our address has changed. Return 0 on success, -1 on failure.
@@ -1093,12 +1271,38 @@ tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
int
get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr)
{
+ /* XXX really, this function should yield a smartlist of addresses. */
+ smartlist_t *addrs;
int sock=-1, r=-1;
struct sockaddr_storage my_addr, target_addr;
socklen_t addr_len;
-
tor_assert(addr);
+ /* Try to do this the smart way if possible. */
+ if ((addrs = get_interface_addresses_raw(severity))) {
+ int rv = -1;
+ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) {
+ if (family != AF_UNSPEC && family != tor_addr_family(a))
+ continue;
+ if (tor_addr_is_loopback(a) ||
+ tor_addr_is_multicast(a))
+ continue;
+
+ tor_addr_copy(addr, a);
+ rv = 0;
+
+ /* If we found a non-internal address, declare success. Otherwise,
+ * keep looking. */
+ if (!tor_addr_is_internal(a, 0))
+ break;
+ } SMARTLIST_FOREACH_END(a);
+
+ SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
+ smartlist_free(addrs);
+ return rv;
+ }
+
+ /* Okay, the smart way is out. */
memset(addr, 0, sizeof(tor_addr_t));
memset(&target_addr, 0, sizeof(target_addr));
/* Don't worry: no packets are sent. We just need to use a real address
diff --git a/src/common/aes.c b/src/common/aes.c
index cec6899817..9487cdd51c 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -17,7 +17,7 @@
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#if OPENSSL_VERSION_NUMBER >= 0x1000001fL
/* See comments about which counter mode implementation to use below. */
#include <openssl/modes.h>
#define USE_OPENSSL_CTR
@@ -45,7 +45,9 @@
* Here we have a counter mode that's faster than the one shipping with
* OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode
* implementation faster than the one here (by about 7%). So we pick which
- * one to used based on the Openssl version above.
+ * one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a
+ * critical bug in that counter mode implementation, so we actually require
+ * that one.)
*/
/*======================================================================*/
diff --git a/src/common/compat.c b/src/common/compat.c
index 33e2864ada..27e0060544 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1634,6 +1634,42 @@ get_parent_directory(char *fname)
return -1;
}
+/** Expand possibly relative path <b>fname</b> to an absolute path.
+ * Return a newly allocated string, possibly equal to <b>fname</b>. */
+char *
+make_path_absolute(char *fname)
+{
+#ifdef WINDOWS
+ char *absfname_malloced = _fullpath(NULL, fname, 1);
+
+ /* We don't want to assume that tor_free can free a string allocated
+ * with malloc. On failure, return fname (it's better than nothing). */
+ char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname);
+ if (absfname_malloced) free(absfname_malloced);
+
+ return absfname;
+#else
+ char path[PATH_MAX+1];
+ char *absfname = NULL;
+
+ tor_assert(fname);
+
+ if (fname[0] == '/') {
+ absfname = tor_strdup(fname);
+ } else {
+ if (getcwd(path, PATH_MAX) != NULL) {
+ tor_asprintf(&absfname, "%s/%s", path, fname);
+ } else {
+ /* If getcwd failed, the best we can do here is keep using the
+ * relative path. (Perhaps / isn't readable by this UID/GID.) */
+ absfname = tor_strdup(fname);
+ }
+ }
+
+ return absfname;
+#endif
+}
+
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
* but works on Windows and Solaris.)
diff --git a/src/common/compat.h b/src/common/compat.h
index a228a46cf8..2db8107a8e 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -335,7 +335,7 @@ struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
#define timeradd(tv1,tv2,tvout) \
do { \
(tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \
- (tvout)->tv_usec = (tv2)->tv_usec + (tv2)->tv_usec; \
+ (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \
if ((tvout)->tv_usec >= 1000000) { \
(tvout)->tv_usec -= 1000000; \
(tvout)->tv_sec++; \
@@ -349,7 +349,7 @@ struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
#define timersub(tv1,tv2,tvout) \
do { \
(tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \
- (tvout)->tv_usec = (tv2)->tv_usec - (tv2)->tv_usec; \
+ (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \
if ((tvout)->tv_usec < 0) { \
(tvout)->tv_usec += 1000000; \
(tvout)->tv_sec--; \
@@ -571,6 +571,7 @@ char *get_user_homedir(const char *username);
#endif
int get_parent_directory(char *fname);
+char *make_path_absolute(char *fname);
int spawn_func(void (*func)(void *), void *data);
void spawn_exit(void) ATTR_NORETURN;
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 350d8edc0a..97b6162606 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -378,6 +378,63 @@ circuit_purpose_to_controller_string(uint8_t purpose)
}
}
+/** Return a string specifying the state of the hidden-service circuit
+ * purpose <b>purpose</b>, or NULL if <b>purpose</b> is not a
+ * hidden-service-related circuit purpose. */
+const char *
+circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
+{
+ switch (purpose)
+ {
+ default:
+ log_fn(LOG_WARN, LD_BUG,
+ "Unrecognized circuit purpose: %d",
+ (int)purpose);
+ tor_fragile_assert();
+ /* fall through */
+
+ case CIRCUIT_PURPOSE_OR:
+ case CIRCUIT_PURPOSE_C_GENERAL:
+ case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
+ case CIRCUIT_PURPOSE_TESTING:
+ case CIRCUIT_PURPOSE_CONTROLLER:
+ return NULL;
+
+ case CIRCUIT_PURPOSE_INTRO_POINT:
+ return "OR_HSSI_ESTABLISHED";
+ case CIRCUIT_PURPOSE_REND_POINT_WAITING:
+ return "OR_HSCR_ESTABLISHED";
+ case CIRCUIT_PURPOSE_REND_ESTABLISHED:
+ return "OR_HS_R_JOINED";
+
+ case CIRCUIT_PURPOSE_C_INTRODUCING:
+ return "HSCI_CONNECTING";
+ case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
+ return "HSCI_INTRO_SENT";
+ case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
+ return "HSCI_DONE";
+
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
+ return "HSCR_CONNECTING";
+ case CIRCUIT_PURPOSE_C_REND_READY:
+ return "HSCR_ESTABLISHED_IDLE";
+ case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
+ return "HSCR_ESTABLISHED_WAITING";
+ case CIRCUIT_PURPOSE_C_REND_JOINED:
+ return "HSCR_JOINED";
+
+ case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
+ return "HSSI_CONNECTING";
+ case CIRCUIT_PURPOSE_S_INTRO:
+ return "HSSI_ESTABLISHED";
+
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
+ return "HSSR_CONNECTING";
+ case CIRCUIT_PURPOSE_S_REND_JOINED:
+ return "HSSR_JOINED";
+ }
+}
+
/** Return a human-readable string for the circuit purpose <b>purpose</b>. */
const char *
circuit_purpose_to_string(uint8_t purpose)
@@ -1222,16 +1279,16 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
} else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING &&
reason != END_CIRC_REASON_TIMEOUT) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
- tor_assert(ocirc->build_state->chosen_exit);
- tor_assert(ocirc->rend_data);
- log_info(LD_REND, "Failed intro circ %s to %s "
- "(building circuit to intro point). "
- "Marking intro point as possibly unreachable.",
- safe_str_client(ocirc->rend_data->onion_address),
+ if (ocirc->build_state->chosen_exit && ocirc->rend_data) {
+ log_info(LD_REND, "Failed intro circ %s to %s "
+ "(building circuit to intro point). "
+ "Marking intro point as possibly unreachable.",
+ safe_str_client(ocirc->rend_data->onion_address),
safe_str_client(build_state_get_exit_nickname(ocirc->build_state)));
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- INTRO_POINT_FAILURE_UNREACHABLE);
+ rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
+ ocirc->rend_data,
+ INTRO_POINT_FAILURE_UNREACHABLE);
+ }
}
if (circ->n_conn) {
circuit_clear_cell_queue(circ, circ->n_conn);
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index dea2813cae..e2298c69af 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -15,6 +15,7 @@
circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
+const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
const char *circuit_purpose_to_string(uint8_t purpose);
void circuit_dump_by_conn(connection_t *conn, int severity);
void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
diff --git a/src/or/config.c b/src/or/config.c
index da4f3c195b..740a9dbfd7 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -3568,6 +3568,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseBridges && options->EntryNodes)
REJECT("You cannot set both UseBridges and EntryNodes.");
+ if (options->EntryNodes && !options->UseEntryGuards)
+ log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. "
+ "EntryNodes will be ignored.");
+
options->_AllowInvalid = 0;
if (options->AllowInvalidNodes) {
SMARTLIST_FOREACH(options->AllowInvalidNodes, const char *, cp, {
@@ -4358,6 +4362,14 @@ find_torrc_filename(int argc, char **argv,
tor_free(fname);
}
fname = expand_filename(argv[i+1]);
+
+ {
+ char *absfname;
+ absfname = make_path_absolute(fname);
+ tor_free(fname);
+ fname = absfname;
+ }
+
*using_default_torrc = 0;
++i;
} else if (ignore_opt && !strcmp(argv[i],ignore_opt)) {
diff --git a/src/or/connection.c b/src/or/connection.c
index 28d8bca12a..3e445166bd 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -817,7 +817,7 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the "
"directory %s needs to exist, and to be accessible only by the "
"user%s account that is running Tor. (On some Unix systems, "
- "anybody who can list a socket can conect to it, so Tor is "
+ "anybody who can list a socket can connect to it, so Tor is "
"being careful.)", escpath, escdir,
options->ControlSocketsGroupWritable ? " and group" : "");
tor_free(escpath);
@@ -1051,7 +1051,12 @@ connection_create_listener(const struct sockaddr *listensockaddr,
}
/** Do basic sanity checking on a newly received socket. Return 0
- * if it looks ok, else return -1. */
+ * if it looks ok, else return -1.
+ *
+ * Notably, some TCP stacks can erroneously have accept() return successfully
+ * with socklen 0, when the client sends an RST before the accept call (as
+ * nmap does). We want to detect that, and not go on with the connection.
+ */
static int
check_sockaddr(struct sockaddr *sa, int len, int level)
{
@@ -1117,14 +1122,14 @@ connection_handle_listener_read(connection_t *conn, int new_type)
tor_socket_t news; /* the new socket */
connection_t *newconn;
/* information about the remote peer when connecting to other routers */
- char addrbuf[256];
- struct sockaddr *remote = (struct sockaddr*)addrbuf;
+ struct sockaddr_storage addrbuf;
+ struct sockaddr *remote = (struct sockaddr*)&addrbuf;
/* length of the remote address. Must be whatever accept() needs. */
socklen_t remotelen = (socklen_t)sizeof(addrbuf);
const or_options_t *options = get_options();
tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in));
- memset(addrbuf, 0, sizeof(addrbuf));
+ memset(&addrbuf, 0, sizeof(addrbuf));
news = tor_accept_socket(conn->s,remote,&remotelen);
if (!SOCKET_OK(news)) { /* accept() error */
@@ -1161,21 +1166,9 @@ connection_handle_listener_read(connection_t *conn, int new_type)
uint16_t port;
if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
log_info(LD_NET,
- "accept() returned a strange address; trying getsockname().");
- remotelen=sizeof(addrbuf);
- memset(addrbuf, 0, sizeof(addrbuf));
- if (getsockname(news, remote, &remotelen)<0) {
- int e = tor_socket_errno(news);
- log_warn(LD_NET, "getsockname() for new connection failed: %s",
- tor_socket_strerror(e));
- } else {
- if (check_sockaddr((struct sockaddr*)addrbuf, remotelen,
- LOG_WARN) < 0) {
- log_warn(LD_NET,"Something's wrong with this conn. Closing it.");
- tor_close_socket(news);
- return 0;
- }
- }
+ "accept() returned a strange address; closing connection.");
+ tor_close_socket(news);
+ return 0;
}
if (check_sockaddr_family_match(remote->sa_family, conn) < 0) {
@@ -1303,7 +1296,7 @@ connection_connect(connection_t *conn, const char *address,
{
tor_socket_t s;
int inprogress = 0;
- char addrbuf[256];
+ struct sockaddr_storage addrbuf;
struct sockaddr *dest_addr;
int dest_addr_len;
const or_options_t *options = get_options();
@@ -1371,8 +1364,8 @@ connection_connect(connection_t *conn, const char *address,
if (options->ConstrainedSockets)
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
- memset(addrbuf,0,sizeof(addrbuf));
- dest_addr = (struct sockaddr*) addrbuf;
+ memset(&addrbuf,0,sizeof(addrbuf));
+ dest_addr = (struct sockaddr*) &addrbuf;
dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf));
tor_assert(dest_addr_len > 0);
@@ -1963,7 +1956,7 @@ connection_mark_all_noncontrol_listeners(void)
} SMARTLIST_FOREACH_END(conn);
}
-/** Mark every external conection not used for controllers for close. */
+/** Mark every external connection not used for controllers for close. */
void
connection_mark_all_noncontrol_connections(void)
{
@@ -2960,6 +2953,9 @@ connection_handle_event_cb(struct bufferevent *bufev, short event, void *arg)
{
connection_t *conn = arg;
(void) bufev;
+ if (conn->marked_for_close)
+ return;
+
if (event & BEV_EVENT_CONNECTED) {
tor_assert(connection_state_is_connecting(conn));
if (connection_finished_connecting(conn)<0)
diff --git a/src/or/control.c b/src/or/control.c
index 20caabf0c1..c9d3765ad3 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1780,6 +1780,88 @@ getinfo_helper_dir(control_connection_t *control_conn,
return 0;
}
+/** Allocate and return a description of <b>circ</b>'s current status,
+ * including its path (if any). */
+static char *
+circuit_describe_status_for_controller(origin_circuit_t *circ)
+{
+ char *rv;
+ smartlist_t *descparts = smartlist_create();
+
+ {
+ char *vpath = circuit_list_path_for_controller(circ);
+ if (*vpath) {
+ smartlist_add(descparts, vpath);
+ } else {
+ tor_free(vpath); /* empty path; don't put an extra space in the result */
+ }
+ }
+
+ {
+ char *buildflags = NULL;
+ cpath_build_state_t *build_state = circ->build_state;
+ smartlist_t *flaglist = smartlist_create();
+ char *flaglist_joined;
+
+ if (build_state->onehop_tunnel)
+ smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL");
+ if (build_state->is_internal)
+ smartlist_add(flaglist, (void *)"IS_INTERNAL");
+ if (build_state->need_capacity)
+ smartlist_add(flaglist, (void *)"NEED_CAPACITY");
+ if (build_state->need_uptime)
+ smartlist_add(flaglist, (void *)"NEED_UPTIME");
+
+ /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */
+ if (smartlist_len(flaglist)) {
+ flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL);
+
+ tor_asprintf(&buildflags, "BUILD_FLAGS=%s", flaglist_joined);
+ smartlist_add(descparts, buildflags);
+
+ tor_free(flaglist_joined);
+ }
+
+ smartlist_free(flaglist);
+ }
+
+ {
+ char *purpose = NULL;
+ tor_asprintf(&purpose, "PURPOSE=%s",
+ circuit_purpose_to_controller_string(circ->_base.purpose));
+ smartlist_add(descparts, purpose);
+ }
+
+ {
+ char *hs_state_arg = NULL;
+ const char *hs_state =
+ circuit_purpose_to_controller_hs_state_string(circ->_base.purpose);
+
+ if (hs_state != NULL) {
+ tor_asprintf(&hs_state_arg, "HS_STATE=%s",
+ hs_state);
+
+ smartlist_add(descparts, hs_state_arg);
+ }
+ }
+
+ if (circ->rend_data != NULL) {
+ char *rend_query_arg = NULL;
+
+ tor_asprintf(&rend_query_arg, "REND_QUERY=%s",
+ circ->rend_data->onion_address);
+
+ smartlist_add(descparts, rend_query_arg);
+ }
+
+ rv = smartlist_join_strings(descparts, " ", 0, NULL);
+
+ SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
+ smartlist_free(descparts);
+
+ return rv;
+}
+
/** Implementation helper for GETINFO: knows how to generate summaries of the
* current states of things we send events about. */
static int
@@ -1789,33 +1871,33 @@ getinfo_helper_events(control_connection_t *control_conn,
{
(void) control_conn;
if (!strcmp(question, "circuit-status")) {
- circuit_t *circ;
+ circuit_t *circ_;
smartlist_t *status = smartlist_create();
- for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
- char *s, *path;
+ for (circ_ = _circuit_get_global_list(); circ_; circ_ = circ_->next) {
+ origin_circuit_t *circ;
+ char *s, *circdesc;
size_t slen;
const char *state;
- const char *purpose;
- if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
+ if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close)
continue;
+ circ = TO_ORIGIN_CIRCUIT(circ_);
- path = circuit_list_path_for_controller(TO_ORIGIN_CIRCUIT(circ));
-
- if (circ->state == CIRCUIT_STATE_OPEN)
+ if (circ->_base.state == CIRCUIT_STATE_OPEN)
state = "BUILT";
- else if (strlen(path))
+ else if (circ->cpath)
state = "EXTENDED";
else
state = "LAUNCHED";
- purpose = circuit_purpose_to_controller_string(circ->purpose);
- slen = strlen(path)+strlen(state)+strlen(purpose)+30;
+ circdesc = circuit_describe_status_for_controller(circ);
+
+ slen = strlen(circdesc)+strlen(state)+30;
s = tor_malloc(slen+1);
- tor_snprintf(s, slen, "%lu %s%s%s PURPOSE=%s",
- (unsigned long)TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- state, *path ? " " : "", path, purpose);
+ tor_snprintf(s, slen, "%lu %s%s%s",
+ (unsigned long)circ->global_identifier,
+ state, *circdesc ? " " : "", circdesc);
smartlist_add(status, s);
- tor_free(path);
+ tor_free(circdesc);
}
*answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
@@ -3237,7 +3319,7 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
int reason_code)
{
const char *status;
- char extended_buf[96];
+ char reasons[64] = "";
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
tor_assert(circ);
@@ -3254,36 +3336,32 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
return 0;
}
- tor_snprintf(extended_buf, sizeof(extended_buf), "PURPOSE=%s",
- circuit_purpose_to_controller_string(circ->_base.purpose));
-
if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) {
const char *reason_str = circuit_end_reason_to_control_string(reason_code);
- char *reason = NULL;
- size_t n=strlen(extended_buf);
+ char unk_reason_buf[16];
if (!reason_str) {
- reason = tor_malloc(16);
- tor_snprintf(reason, 16, "UNKNOWN_%d", reason_code);
- reason_str = reason;
+ tor_snprintf(unk_reason_buf, 16, "UNKNOWN_%d", reason_code);
+ reason_str = unk_reason_buf;
}
if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) {
- tor_snprintf(extended_buf+n, sizeof(extended_buf)-n,
+ tor_snprintf(reasons, sizeof(reasons),
" REASON=DESTROYED REMOTE_REASON=%s", reason_str);
} else {
- tor_snprintf(extended_buf+n, sizeof(extended_buf)-n,
+ tor_snprintf(reasons, sizeof(reasons),
" REASON=%s", reason_str);
}
- tor_free(reason);
}
{
- char *vpath = circuit_list_path_for_controller(circ);
- const char *sp = strlen(vpath) ? " " : "";
+ char *circdesc = circuit_describe_status_for_controller(circ);
+ const char *sp = strlen(circdesc) ? " " : "";
send_control_event(EVENT_CIRCUIT_STATUS, ALL_FORMATS,
- "650 CIRC %lu %s%s%s %s\r\n",
+ "650 CIRC %lu %s%s%s%s\r\n",
(unsigned long)circ->global_identifier,
- status, sp, vpath, extended_buf);
- tor_free(vpath);
+ status, sp,
+ circdesc,
+ reasons);
+ tor_free(circdesc);
}
return 0;
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f4bbca8500..94a415fe21 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -388,19 +388,20 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
- /* Tor 0.2.0.26-rc is the oldest version that currently caches the right
- * directory information. Once more of them die off, we should raise this
- * minimum. */
- if (platform && !tor_version_as_new_as(platform,"0.2.0.26-rc")) {
+ /* Versions before Tor 0.2.1.30 have known security issues that
+ * make them unsuitable for the current network. */
+ if (platform && !tor_version_as_new_as(platform,"0.2.1.30")) {
if (msg)
- *msg = "Tor version is far too old to work.";
- return FP_REJECT;
- } else if (platform && tor_version_as_new_as(platform,"0.2.1.3-alpha")
- && !tor_version_as_new_as(platform, "0.2.1.19")) {
- /* These versions mishandled RELAY_EARLY cells on rend circuits. */
- if (msg)
- *msg = "Tor version is too buggy to work.";
+ *msg = "Tor version is insecure. Please upgrade!";
return FP_REJECT;
+ } else if (platform && tor_version_as_new_as(platform,"0.2.2.1-alpha")) {
+ /* Versions from 0.2.2.1-alpha...0.2.2.20-alpha have known security
+ * issues that make them unusable for the current network */
+ if (!tor_version_as_new_as(platform, "0.2.2.21-alpha")) {
+ if (msg)
+ *msg = "Tor version is insecure. Please upgrade!";
+ return FP_REJECT;
+ }
}
result = dirserv_get_name_status(id_digest, nickname);
diff --git a/src/or/relay.c b/src/or/relay.c
index 6cf4b73a5f..90d8015cb8 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1188,13 +1188,40 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
connection_mark_and_flush(TO_CONN(conn));
}
return 0;
- case RELAY_COMMAND_EXTEND:
+ case RELAY_COMMAND_EXTEND: {
+ static uint64_t total_n_extend=0, total_nonearly=0;
+ total_n_extend++;
if (conn) {
log_fn(LOG_PROTOCOL_WARN, domain,
"'extend' cell received for non-zero stream. Dropping.");
return 0;
}
+ if (cell->command != CELL_RELAY_EARLY &&
+ !networkstatus_get_param(NULL,"AllowNonearlyExtend",0,0,1)) {
+#define EARLY_WARNING_INTERVAL 3600
+ static ratelim_t early_warning_limit =
+ RATELIM_INIT(EARLY_WARNING_INTERVAL);
+ char *m;
+ if (cell->command == CELL_RELAY) {
+ ++total_nonearly;
+ if ((m = rate_limit_log(&early_warning_limit, approx_time()))) {
+ double percentage = ((double)total_nonearly)/total_n_extend;
+ percentage *= 100;
+ log_fn(LOG_PROTOCOL_WARN, domain, "EXTEND cell received, "
+ "but not via RELAY_EARLY. Dropping.%s", m);
+ log_fn(LOG_PROTOCOL_WARN, domain, " (We have dropped %.02f%% of "
+ "all EXTEND cells for this reason)", percentage);
+ tor_free(m);
+ }
+ } else {
+ log_fn(LOG_WARN, domain,
+ "EXTEND cell received, in a cell with type %d! Dropping.",
+ cell->command);
+ }
+ return 0;
+ }
return circuit_extend(cell, circ);
+ }
case RELAY_COMMAND_EXTENDED:
if (!layer_hint) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -2495,10 +2522,6 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
queue = &orcirc->p_conn_cells;
streams_blocked = circ->streams_blocked_on_p_conn;
}
- if (cell->command == CELL_RELAY_EARLY && orconn->link_proto < 2) {
- /* V1 connections don't understand RELAY_EARLY. */
- cell->command = CELL_RELAY;
- }
cell_queue_append_packed_copy(queue, cell);
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 9d8e1fe8c5..cf9c8f91d5 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -613,12 +613,11 @@ test_addr_ip6_helpers(void)
/* get interface addresses */
r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
-#if 0
- tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf));
- printf("\nv4 address: %s (family=%d)", buf, IN_FAMILY(&t1));
- tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf));
- printf("\nv6 address: %s (family=%d)", buf, IN_FAMILY(&t2));
-#endif
+
+ TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1),
+ tor_addr_family(&t1)));
+ TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2),
+ tor_addr_family(&t2)));
done:
;