diff --git a/changes/bug12160 b/changes/bug12160 new file mode 100644 index 0000000000..2a7ace3410 --- /dev/null +++ b/changes/bug12160 @@ -0,0 +1,4 @@ + o Bugfixes + - Correctly update the local mark on the controlling channel when changing + the address of an or_connection_t after the handshake. Fixes bug #12160; + bugfix on 0.2.4.4-alpha. diff --git a/src/or/channel.c b/src/or/channel.c index 4129839fea..c8c92633b1 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -3759,6 +3759,23 @@ channel_mark_local(channel_t *chan) chan->is_local = 1; } +/** + * Mark a channel as remote + * + * This internal-only function should be called by the lower layer if the + * channel is not to a local address but has previously been marked local. + * See channel_is_local() above or the description of the is_local bit in + * channel.h + */ + +void +channel_mark_remote(channel_t *chan) +{ + tor_assert(chan); + + chan->is_local = 0; +} + /** * Test outgoing flag * diff --git a/src/or/channel.h b/src/or/channel.h index 3e164c6892..148199235a 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -349,6 +349,7 @@ void channel_clear_remote_end(channel_t *chan); void channel_mark_local(channel_t *chan); void channel_mark_incoming(channel_t *chan); void channel_mark_outgoing(channel_t *chan); +void channel_mark_remote(channel_t *chan); void channel_set_identity_digest(channel_t *chan, const char *identity_digest); void channel_set_remote_end(channel_t *chan, diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 632bc328b7..245e33583b 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -156,7 +156,18 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, tlschan, U64_PRINTF_ARG(chan->global_identifier)); - if (is_local_addr(addr)) channel_mark_local(chan); + if (is_local_addr(addr)) { + log_debug(LD_CHANNEL, + "Marking new outgoing channel " U64_FORMAT " at %p as local", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_local(chan); + } else { + log_debug(LD_CHANNEL, + "Marking new outgoing channel " U64_FORMAT " at %p as remote", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_remote(chan); + } + channel_mark_outgoing(chan); /* Set up or_connection stuff */ @@ -286,7 +297,18 @@ channel_tls_handle_incoming(or_connection_t *orconn) tlschan->conn = orconn; orconn->chan = tlschan; - if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan); + if (is_local_addr(&(TO_CONN(orconn)->addr))) { + log_debug(LD_CHANNEL, + "Marking new incoming channel " U64_FORMAT " at %p as local", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_local(chan); + } else { + log_debug(LD_CHANNEL, + "Marking new incoming channel " U64_FORMAT " at %p as remote", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_remote(chan); + } + channel_mark_incoming(chan); /* Register it */ @@ -1208,6 +1230,44 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn) } } +/** + * Update channel marks after connection_or.c has changed an address + * + * This is called from connection_or_init_conn_from_address() after the + * connection's _base.addr or real_addr fields have potentially been changed + * so we can recalculate the local mark. Notably, this happens when incoming + * connections are reverse-proxied and we only learn the real address of the + * remote router by looking it up in the consensus after we finish the + * handshake and know an authenticated identity digest. + */ + +void +channel_tls_update_marks(or_connection_t *conn) +{ + channel_t *chan = NULL; + + tor_assert(conn); + tor_assert(conn->chan); + + chan = TLS_CHAN_TO_BASE(conn->chan); + + if (is_local_addr(&(TO_CONN(conn)->addr))) { + if (!channel_is_local(chan)) { + log_debug(LD_CHANNEL, + "Marking channel " U64_FORMAT " at %p as local", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_local(chan); + } + } else { + if (channel_is_local(chan)) { + log_debug(LD_CHANNEL, + "Marking channel " U64_FORMAT " at %p as remote", + U64_PRINTF_ARG(chan->global_identifier), chan); + channel_mark_remote(chan); + } + } +} + /** * Check if this cell type is allowed before the handshake is finished * diff --git a/src/or/channeltls.h b/src/or/channeltls.h index b4a7e2beac..c872a09d79 100644 --- a/src/or/channeltls.h +++ b/src/or/channeltls.h @@ -49,6 +49,7 @@ void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan, uint8_t state); void channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn); +void channel_tls_update_marks(or_connection_t *conn); /* Cleanup at shutdown */ void channel_tls_free_all(void); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 16f87349fc..c372270b4c 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -923,6 +923,15 @@ connection_or_init_conn_from_address(or_connection_t *conn, tor_free(conn->base_.address); conn->base_.address = tor_dup_addr(addr); } + + /* + * We have to tell channeltls.c to update the channel marks (local, in + * particular), since we may have changed the address. + */ + + if (conn->chan) { + channel_tls_update_marks(conn); + } } /** These just pass all the is_bad_for_new_circs manipulation on to