commit 39a017809b6e7f8f779cfa0b4ebea3c0209bef0c Author: Andrea Shepard andrea@torproject.org Date: Fri Sep 5 11:08:46 2014 -0700
Correctly update channel local mark when address of incoming connection changes after handshake; fixes bug #12160 --- changes/bug12160 | 4 +++ src/or/channel.c | 17 +++++++++++++ src/or/channel.h | 1 + src/or/channeltls.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- src/or/channeltls.h | 1 + src/or/connection_or.c | 9 +++++++ 6 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/changes/bug12160 b/changes/bug12160 new file mode 100644 index 0000000..2a7ace3 --- /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 ffd6849..b2b670e 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -3760,6 +3760,23 @@ channel_mark_local(channel_t *chan) }
/** + * 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 * * This function gets the outgoing flag; this is the inverse of the incoming diff --git a/src/or/channel.h b/src/or/channel.h index 3e164c6..1481992 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 632bc32..245e335 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 */ @@ -1209,6 +1231,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 * * Return true if <b>command</b> is a cell command that's allowed to start a diff --git a/src/or/channeltls.h b/src/or/channeltls.h index b4a7e2b..c872a09 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 16f8734..c372270 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
tor-commits@lists.torproject.org