diff options
-rw-r--r-- | changes/bug1848 | 3 | ||||
-rw-r--r-- | changes/log-ratelim | 7 | ||||
-rw-r--r-- | changes/openbsd-sysheaders | 4 | ||||
-rw-r--r-- | configure.in | 11 | ||||
-rw-r--r-- | doc/spec/rend-spec.txt | 55 | ||||
-rw-r--r-- | src/common/util.c | 43 | ||||
-rw-r--r-- | src/common/util.h | 27 | ||||
-rw-r--r-- | src/or/command.c | 9 | ||||
-rw-r--r-- | src/or/connection.c | 12 | ||||
-rw-r--r-- | src/or/onion.c | 11 | ||||
-rw-r--r-- | src/or/or.h | 3 |
11 files changed, 147 insertions, 38 deletions
diff --git a/changes/bug1848 b/changes/bug1848 new file mode 100644 index 0000000000..db00e17f83 --- /dev/null +++ b/changes/bug1848 @@ -0,0 +1,3 @@ + o Minor bugfixes: + - Squash a compile warning on OpenBSD. Reported by Tas, fixes bug 1848. + diff --git a/changes/log-ratelim b/changes/log-ratelim new file mode 100644 index 0000000000..612a510fdf --- /dev/null +++ b/changes/log-ratelim @@ -0,0 +1,7 @@ + o Minor bugfixes + - Rate-limit "Failed to hand off onionskin" warnings. + + o Minor features + - When logging a rate-limited warning, we now mention how many messages + got suppressed since the last warning. + diff --git a/changes/openbsd-sysheaders b/changes/openbsd-sysheaders new file mode 100644 index 0000000000..2babde2d78 --- /dev/null +++ b/changes/openbsd-sysheaders @@ -0,0 +1,4 @@ + o Minor bugfixes: + - When building with --enable-gcc-warnings on OpenBSD, disable + warnings in system headers. This makes --enable-gcc-warnings + pass on OpenBSD 4.8.
\ No newline at end of file diff --git a/configure.in b/configure.in index 917be20ed8..cb07b2f7b0 100644 --- a/configure.in +++ b/configure.in @@ -869,6 +869,15 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy have_shorten64_flag=no) CFLAGS="$save_CFLAGS" + case $host in + *-*-openbsd*) + # Some OpenBSD versions (like 4.8) have -Wsystem-headers by default. + # That's fine, except that the headers don't pass -Wredundant-decls. + # Therefore, let's disable -Wsystem-headers when we're building + # with maximal warnings on OpenBSD. + CFLAGS="$CFLAGS -Wno-system-headers" ;; + esac + CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat=2 -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum" if test x$enable_gcc_warnings = xyes; then CFLAGS="$CFLAGS -Werror" @@ -876,7 +885,7 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy # Disabled, so we can use mallinfo(): -Waggregate-return - if test x$have_gcc4 = xyes ; then + if test x$have_gcc4 = xyes ; then # These warnings break gcc 3.3.5 and work on gcc 4.0.2 CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement -Wold-style-definition" fi diff --git a/doc/spec/rend-spec.txt b/doc/spec/rend-spec.txt index 12e20df659..3c14ebc662 100644 --- a/doc/spec/rend-spec.txt +++ b/doc/spec/rend-spec.txt @@ -150,7 +150,7 @@ The first time the OP provides an advertised service, it generates a public/private keypair (stored locally). - The OP choses a small number of Tor servers as introduction points. + The OP chooses a small number of Tor servers as introduction points. The OP establishes a new introduction circuit to each introduction point. These circuits MUST NOT be used for anything but hidden service introduction. To establish the introduction, Bob sends a @@ -238,6 +238,9 @@ permanent-id = H(public-key)[:10] + Note: If Bob's OP has "stealth" authorization enabled (see Section 2.2), + it uses the client key in place of the public hidden service key. + "H(time-period | descriptor-cookie | replica)" is the (possibly secret) id part that is necessary to verify that the hidden service is the true originator of this descriptor and that is therefore contained @@ -668,8 +671,8 @@ circuit. (If the PK_ID is unrecognized, the RELAY_COMMAND_INTRODUCE1 cell is discarded.) - After sending the RELAY_COMMAND_INTRODUCE2 cell, the OR replies to Alice - with an empty RELAY_COMMAND_INTRODUCE_ACK cell. If no + After sending the RELAY_COMMAND_INTRODUCE2 cell to Bob, the OR replies to + Alice with an empty RELAY_COMMAND_INTRODUCE_ACK cell. If no RELAY_COMMAND_INTRODUCE2 cell can be sent, the OR replies to Alice with a non-empty cell to indicate an error. (The semantics of the cell body may be determined later; the current implementation sends a single '1' byte on @@ -759,11 +762,11 @@ 2.1. Service with large-scale client authorization The first client authorization protocol aims at performing access control - while consuming as few additional resources as possible. A service - provider should be able to permit access to a large number of clients - while denying access for everyone else. However, the price for - scalability is that the service won't be able to hide its activity from - unauthorized or formerly authorized clients. + while consuming as few additional resources as possible. This is the "basic" + authorization protocol. A service provider should be able to permit access + to a large number of clients while denying access for everyone else. + However, the price for scalability is that the service won't be able to hide + its activity from unauthorized or formerly authorized clients. The main idea of this protocol is to encrypt the introduction-point part in hidden service descriptors to authorized clients using symmetric keys. @@ -822,19 +825,19 @@ 2.2. Authorization for limited number of clients A second, more sophisticated client authorization protocol goes the extra - mile of hiding service activity from unauthorized clients. With all else - being equal to the preceding authorization protocol, the second protocol - publishes hidden service descriptors for each user separately and gets - along with encrypting the introduction-point part of descriptors to a - single client. This allows the service to stop publishing descriptors for - removed clients. As long as a removed client cannot link descriptors - issued for other clients to the service, it cannot derive service - activity any more. The downside of this approach is limited scalability. - Even though the distributed storage of descriptors (cf. proposal 114) - tackles the problem of limited scalability to a certain extent, this - protocol should not be used for services with more than 16 clients. (In - fact, Tor should refuse to advertise services for more than this number - of clients.) + mile of hiding service activity from unauthorized clients. This is the + "stealth" authorization protocol. With all else being equal to the preceding + authorization protocol, the second protocol publishes hidden service + descriptors for each user separately and gets along with encrypting the + introduction-point part of descriptors to a single client. This allows the + service to stop publishing descriptors for removed clients. As long as a + removed client cannot link descriptors issued for other clients to the + service, it cannot derive service activity any more. The downside of this + approach is limited scalability. Even though the distributed storage of + descriptors (cf. proposal 114) tackles the problem of limited scalability to + a certain extent, this protocol should not be used for services with more + than 16 clients. (In fact, Tor should refuse to advertise services for more + than this number of clients.) A hidden service generates an asymmetric "client key" and a symmetric "descriptor cookie" for each client. The client key is used as @@ -882,14 +885,16 @@ A hidden service that is meant to perform client authorization adds a new option HiddenServiceAuthorizeClient to its hidden service configuration. This option contains the authorization type which is - either "1" for the protocol described in 2.1 or "2" for the protocol in - 2.2 and a comma-separated list of human-readable client names, so that - Tor can create authorization data for these clients: + either "basic" for the protocol described in 2.1 or "stealth" for the + protocol in 2.2 and a comma-separated list of human-readable client + names, so that Tor can create authorization data for these clients: HiddenServiceAuthorizeClient auth-type client-name,client-name,... If this option is configured, HiddenServiceVersion is automatically - reconfigured to contain only version numbers of 2 or higher. + reconfigured to contain only version numbers of 2 or higher. There is + a maximum of 512 client names for basic auth and a maximum of 16 for + stealth auth. Tor stores all generated authorization data for the authorization protocols described in Sections 2.1 and 2.2 in a new file using the diff --git a/src/common/util.c b/src/common/util.c index 0f50dfedea..1d770458f7 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1578,6 +1578,49 @@ ftime_definitely_before(time_t now, time_t when) } /* ===== + * Rate limiting + * ===== */ + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number + * of calls to rate_limit_is_ready (including this one!) since the last time + * rate_limit_is_ready returned nonzero. Otherwise return 0. */ +static int +rate_limit_is_ready(ratelim_t *lim, time_t now) +{ + if (lim->rate + lim->last_allowed <= now) { + int res = lim->n_calls_since_last_time + 1; + lim->last_allowed = now; + lim->n_calls_since_last_time = 0; + return res; + } else { + ++lim->n_calls_since_last_time; + return 0; + } +} + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly + * allocated string indicating how many messages were suppressed, suitable to + * append to a log message. Otherwise return NULL. */ +char * +rate_limit_log(ratelim_t *lim, time_t now) +{ + int n; + if ((n = rate_limit_is_ready(lim, now))) { + if (n == 1) { + return tor_strdup(""); + } else { + char *cp=NULL; + tor_asprintf(&cp, + " [%d similar message(s) suppressed in last %d seconds]", + n-1, lim->rate); + return cp; + } + } else { + return NULL; + } +} + +/* ===== * File helpers * ===== */ diff --git a/src/common/util.h b/src/common/util.h index ba38f4c7ed..3a3a87378a 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -252,6 +252,33 @@ int ftime_maybe_before(time_t now, time_t when); int ftime_definitely_after(time_t now, time_t when); int ftime_definitely_before(time_t now, time_t when); +/* Rate-limiter */ + +/** A ratelim_t remembers how often an event is occurring, and how often + * it's allowed to occur. Typical usage is something like: + * + <pre> + if (possibly_very_frequent_event()) { + const int INTERVAL = 300; + static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); + char *m; + if ((m = rate_limit_log(&warning_limit, approx_time()))) { + log_warn(LD_GENERAL, "The event occurred!%s", m); + tor_free(m); + } + } + </pre> + */ +typedef struct ratelim_t { + int rate; + time_t last_allowed; + int n_calls_since_last_time; +} ratelim_t; + +#define RATELIM_INIT(r) { (r), 0, 0 } + +char *rate_limit_log(ratelim_t *lim, time_t now); + /* File helpers */ ssize_t write_all(int fd, const char *buf, size_t count, int isSocket); ssize_t read_all(int fd, char *buf, size_t count, int isSocket); diff --git a/src/or/command.c b/src/or/command.c index 0460e25c25..ea0bbea1e5 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -288,7 +288,14 @@ command_process_create_cell(cell_t *cell, or_connection_t *conn) /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { - log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing."); +#define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60) + static ratelim_t handoff_warning = + RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL); + char *m; + if ((m = rate_limit_log(&handoff_warning, approx_time()))) { + log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m); + tor_free(m); + } circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } diff --git a/src/or/connection.c b/src/or/connection.c index c040be041e..91ce74b5b0 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -839,13 +839,13 @@ static void warn_too_many_conns(void) { #define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60) - static time_t last_warned = 0; - time_t now = time(NULL); - int n_conns = get_n_open_sockets(); - if (last_warned + WARN_TOO_MANY_CONNS_INTERVAL < now) { + static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL); + char *m; + if ((m = rate_limit_log(&last_warned, approx_time()))) { + int n_conns = get_n_open_sockets(); log_warn(LD_NET,"Failing because we have %d connections already. Please " - "raise your ulimit -n.", n_conns); - last_warned = now; + "raise your ulimit -n.%s", n_conns, m); + tor_free(m); control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d", n_conns); } diff --git a/src/or/onion.c b/src/or/onion.c index ebc3583648..fa001656e6 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -63,15 +63,16 @@ onion_pending_add(or_circuit_t *circ, char *onionskin) if (ol_length >= get_options()->MaxOnionsPending) { #define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) - static time_t last_warned = 0; - time_t now = time(NULL); - if (last_warned + WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL < now) { + static ratelim_t last_warned = + RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); + char *m; + if ((m = rate_limit_log(&last_warned, approx_time()))) { log_warn(LD_GENERAL, "Your computer is too slow to handle this many circuit " "creation requests! Please consider using the " "MaxAdvertisedBandwidth config option or choosing a more " - "restricted exit policy."); - last_warned = now; + "restricted exit policy.%s",m); + tor_free(m); } tor_free(tmp); return -1; diff --git a/src/or/or.h b/src/or/or.h index e6307e3eea..48641c8115 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -59,6 +59,9 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif |