diff options
-rw-r--r-- | changes/bug40281 | 6 | ||||
-rw-r--r-- | changes/ticket40257 | 3 | ||||
-rw-r--r-- | changes/ticket40279 | 4 | ||||
-rw-r--r-- | src/core/mainloop/connection.c | 2 | ||||
-rw-r--r-- | src/feature/metrics/metrics.c | 21 | ||||
-rw-r--r-- | src/feature/metrics/metrics.h | 1 | ||||
-rw-r--r-- | src/feature/nodelist/networkstatus.c | 9 | ||||
-rw-r--r-- | src/feature/relay/router.c | 33 | ||||
-rw-r--r-- | src/test/test_metrics.c | 32 |
9 files changed, 88 insertions, 23 deletions
diff --git a/changes/bug40281 b/changes/bug40281 new file mode 100644 index 0000000000..0708039f04 --- /dev/null +++ b/changes/bug40281 @@ -0,0 +1,6 @@ + o Minor bugfixes (logging): + - Avoid a spurious log message about missing subprotocol versions, when + the consensus that we're reading from is older than the current + release. . Previously we had made this message nonfatal in this case, + but in practice, it is never relevant when the consensus is older than + the current release. Fixes bug 40281; bugfix on 0.4.0.1-alpha. diff --git a/changes/ticket40257 b/changes/ticket40257 new file mode 100644 index 0000000000..4bcebc45a1 --- /dev/null +++ b/changes/ticket40257 @@ -0,0 +1,3 @@ + o Minor bugfixes (metrics port): + - Fix a bug warning when the socket was unexpectedly closed. Fixes bug + 40257; bugfix on 0.4.5.1-alpha diff --git a/changes/ticket40279 b/changes/ticket40279 new file mode 100644 index 0000000000..351db40789 --- /dev/null +++ b/changes/ticket40279 @@ -0,0 +1,4 @@ + o Major bugfixes (IPv6, relay): + - Fix a bug that prevented a relay to publish its descriptor in the case of + an auto-discovered IPv6 that was found unreachable for which we always + publish if the IPv4 is correct. Fixes bug 40279; bugfix on 0.4.5.1-alpha. diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 3d551c4ba8..85cdec6e1e 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -5242,6 +5242,8 @@ connection_reached_eof(connection_t *conn) return connection_dir_reached_eof(TO_DIR_CONN(conn)); case CONN_TYPE_CONTROL: return connection_control_reached_eof(TO_CONTROL_CONN(conn)); + case CONN_TYPE_METRICS: + return metrics_connection_reached_eof(conn); default: log_err(LD_BUG,"got unexpected conn type %d.", conn->type); tor_fragile_assert(); diff --git a/src/feature/metrics/metrics.c b/src/feature/metrics/metrics.c index 886182bc90..7a77ab1104 100644 --- a/src/feature/metrics/metrics.c +++ b/src/feature/metrics/metrics.c @@ -20,6 +20,7 @@ #include "lib/net/address.h" #include "core/mainloop/connection.h" +#include "core/or/connection_or.h" #include "core/or/connection_st.h" #include "core/or/policies.h" #include "core/or/port_cfg_st.h" @@ -93,7 +94,8 @@ metrics_get_output(const metrics_format_t fmt) /** Process what is in the inbuf of this connection of type metrics. * - * Return 0 on success else -1 on error which will close the connection. */ + * Return 0 on success else -1 on error for which the connection is marked for + * close. */ int metrics_connection_process_inbuf(connection_t *conn) { @@ -111,13 +113,14 @@ metrics_connection_process_inbuf(connection_t *conn) goto err; } - const int http_status = fetch_from_buf_http(conn->inbuf, &headers, 1024, - NULL, NULL, 1024, 0); + const int http_status = + connection_fetch_from_buf_http(conn, &headers, 1024, NULL, NULL, 1024, 0); if (http_status < 0) { errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n"; goto err; } else if (http_status == 0) { /* no HTTP request yet. */ + ret = 0; goto done; } @@ -155,6 +158,7 @@ metrics_connection_process_inbuf(connection_t *conn) log_info(LD_EDGE, "HTTP metrics error: saying %s", escaped(errmsg)); connection_buf_add(errmsg, strlen(errmsg), conn); } + connection_mark_and_flush(conn); done: tor_free(headers); @@ -243,6 +247,17 @@ metrics_parse_ports(or_options_t *options, smartlist_t *ports, return ret; } +/** Called when conn has gotten its socket closed. */ +int +metrics_connection_reached_eof(connection_t *conn) +{ + tor_assert(conn); + + log_info(LD_EDGE, "Metrics connection reached EOF. Closing."); + connection_mark_for_close(conn); + return 0; +} + /** Initialize the subsystem. */ void metrics_init(void) diff --git a/src/feature/metrics/metrics.h b/src/feature/metrics/metrics.h index b4bbe28b27..858722de59 100644 --- a/src/feature/metrics/metrics.h +++ b/src/feature/metrics/metrics.h @@ -27,6 +27,7 @@ buf_t *metrics_get_output(const metrics_format_t fmt); /* Connection. */ int metrics_connection_process_inbuf(struct connection_t *conn); +int metrics_connection_reached_eof(struct connection_t *conn); /* Configuration. */ int metrics_parse_ports(or_options_t *options, smartlist_t *ports, diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index ece3c9e059..80940e6092 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -2723,6 +2723,13 @@ networkstatus_check_required_protocols(const networkstatus_t *ns, const bool consensus_postdates_this_release = ns->valid_after >= tor_get_approx_release_date(); + if (! consensus_postdates_this_release) { + // We can't meaningfully warn about this case: This consensus is from + // before we were released, so whatever is says about required or + // recommended versions may no longer be true. + return 0; + } + tor_assert(warning_out); if (client_mode) { @@ -2740,7 +2747,7 @@ networkstatus_check_required_protocols(const networkstatus_t *ns, "%s on the Tor network. The missing protocols are: %s", func, missing); tor_free(missing); - return consensus_postdates_this_release ? 1 : 0; + return 1; } if (! protover_all_supported(recommended, &missing)) { diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 4bc71eb486..0be3eec1dd 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -138,6 +138,18 @@ static authority_cert_t *legacy_key_certificate = NULL; * used by tor-gencert to sign new signing keys and make new key * certificates. */ +/** Indicate if the IPv6 address should be omitted from the descriptor when + * publishing it. This can happen if the IPv4 is reachable but the + * auto-discovered IPv6 is not. We still publish the descriptor. + * + * Only relays should look at this and only for their descriptor. + * + * XXX: The real harder fix is to never put in the routerinfo_t a non + * reachable address and instead use the last resolved address cache to do + * reachability test or anything that has to do with what address tor thinks + * it has. */ +static bool omit_ipv6_on_publish = false; + /** Return a readonly string with human readable description * of <b>err</b>. */ @@ -1396,7 +1408,11 @@ decide_if_publishable_server(void) return 0; } } - if (!router_orport_seems_reachable(options, AF_INET6)) { + /* We could be flagged to omit the IPv6 and if so, don't check for + * reachability on the IPv6. This can happen if the address was + * auto-discovered but turns out to be non reachable. */ + if (!omit_ipv6_on_publish && + !router_orport_seems_reachable(options, AF_INET6)) { // We have an ipv6 orport, and it doesn't seem reachable. if (!publish_even_when_ipv6_orport_unreachable) { return 0; @@ -2085,7 +2101,8 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) ri->ipv4_dirport = routerconf_find_dir_port(options, 0); /* Optionally check for an IPv6. We still publish without one. */ - if (relay_find_addr_to_publish(options, AF_INET6, RELAY_FIND_ADDR_NO_FLAG, + if (!omit_ipv6_on_publish && + relay_find_addr_to_publish(options, AF_INET6, RELAY_FIND_ADDR_NO_FLAG, &ri->ipv6_addr)) { ri->ipv6_orport = routerconf_find_or_port(options, AF_INET6); router_check_descriptor_address_consistency(&ri->ipv6_addr); @@ -2459,18 +2476,6 @@ router_new_consensus_params(const networkstatus_t *ns) publish_even_when_ipv6_orport_unreachable = ar || ar6; } -/** Indicate if the IPv6 address should be omitted from the descriptor when - * publishing it. This can happen if the IPv4 is reachable but the - * auto-discovered IPv6 is not. We still publish the descriptor. - * - * Only relays should look at this and only for their descriptor. - * - * XXX: The real harder fix is to never put in the routerinfo_t a non - * reachable address and instead use the last resolved address cache to do - * reachability test or anything that has to do with what address tor thinks - * it has. */ -static bool omit_ipv6_on_publish = false; - /** Mark our descriptor out of data iff the IPv6 omit status flag is flipped * it changes from its previous value. * diff --git a/src/test/test_metrics.c b/src/test/test_metrics.c index 96eadc6b43..152dd99d23 100644 --- a/src/test/test_metrics.c +++ b/src/test/test_metrics.c @@ -8,6 +8,7 @@ #define CONFIG_PRIVATE #define CONNECTION_PRIVATE +#define MAINLOOP_PRIVATE #define METRICS_STORE_ENTRY_PRIVATE #include "test/test.h" @@ -17,6 +18,7 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" +#include "core/mainloop/mainloop.h" #include "core/or/connection_st.h" #include "core/or/policies.h" #include "core/or/port_cfg_st.h" @@ -96,43 +98,62 @@ static char _c_buf[256]; #define WRITE(conn, msg) \ buf_add(conn->inbuf, (msg), (strlen(msg))); +/* Free the previous conn object if any and allocate a new connection. In + * order to be allowed, set its address to 1.2.3.4 as per the policy. */ +#define NEW_ALLOWED_CONN() \ + do { \ + close_closeable_connections(); \ + conn = connection_new(CONN_TYPE_METRICS, AF_INET); \ + tor_addr_from_ipv4h(&conn->addr, 0x01020304); \ + } while (0) + static void test_connection(void *arg) { int ret; - connection_t *conn = connection_new(CONN_TYPE_METRICS, AF_INET); + connection_t *conn = NULL; or_options_t *options = get_options_mutable(); (void) arg; + /* Notice that in this test, we will allocate a new connection at every test + * case. This is because the metrics_connection_process_inbuf() marks for + * close the connection in case of an error and thus we can't call again an + * inbuf process function on a marked for close connection. */ + + tor_init_connection_lists(); + /* Setup policy. */ set_metrics_port(options); /* Set 1.2.3.5 IP, we should get rejected. */ + NEW_ALLOWED_CONN(); tor_addr_from_ipv4h(&conn->addr, 0x01020305); ret = metrics_connection_process_inbuf(conn); tt_int_op(ret, OP_EQ, -1); - /* Set 1.2.3.4 so from now on we are allowed to process the inbuf. */ - tor_addr_from_ipv4h(&conn->addr, 0x01020304); - /* No HTTP request yet. */ + NEW_ALLOWED_CONN(); ret = metrics_connection_process_inbuf(conn); - tt_int_op(ret, OP_EQ, -1); + tt_int_op(ret, OP_EQ, 0); + connection_free_minimal(conn); /* Bad request. */ + NEW_ALLOWED_CONN(); WRITE(conn, "HTTP 4.7\r\n\r\n"); ret = metrics_connection_process_inbuf(conn); tt_int_op(ret, OP_EQ, -1); CONTAINS(conn, "HTTP/1.0 400 Bad Request\r\n\r\n"); /* Path not found. */ + NEW_ALLOWED_CONN(); WRITE(conn, "GET /badpath HTTP/1.0\r\n\r\n"); ret = metrics_connection_process_inbuf(conn); tt_int_op(ret, OP_EQ, -1); CONTAINS(conn, "HTTP/1.0 404 Not Found\r\n\r\n"); /* Method not allowed. */ + NEW_ALLOWED_CONN(); WRITE(conn, "POST /something HTTP/1.0\r\n\r\n"); ret = metrics_connection_process_inbuf(conn); tt_int_op(ret, OP_EQ, -1); @@ -140,6 +161,7 @@ test_connection(void *arg) /* Ask for metrics. The content should be above 0. We don't test the * validity of the returned content but it is certainly not an error. */ + NEW_ALLOWED_CONN(); WRITE(conn, "GET /metrics HTTP/1.0\r\n\r\n"); ret = metrics_connection_process_inbuf(conn); tt_int_op(ret, OP_EQ, 0); |