diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/address.c | 206 | ||||
-rw-r--r-- | src/common/aes.c | 6 | ||||
-rw-r--r-- | src/common/compat.c | 36 | ||||
-rw-r--r-- | src/common/compat.h | 5 | ||||
-rw-r--r-- | src/or/circuitlist.c | 75 | ||||
-rw-r--r-- | src/or/circuitlist.h | 1 | ||||
-rw-r--r-- | src/or/config.c | 12 | ||||
-rw-r--r-- | src/or/connection.c | 44 | ||||
-rw-r--r-- | src/or/control.c | 142 | ||||
-rw-r--r-- | src/or/dirserv.c | 23 | ||||
-rw-r--r-- | src/or/relay.c | 33 | ||||
-rw-r--r-- | src/test/test_addr.c | 11 |
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: ; |