2016-10-03 01:34:23 +02:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
2006-02-09 06:46:49 +01:00
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
2007-12-12 22:09:01 +01:00
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2017-03-15 21:13:17 +01:00
|
|
|
* Copyright (c) 2007-2017, The Tor Project, Inc. */
|
2003-04-12 00:11:11 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/**
|
|
|
|
* \file connection_edge.c
|
2004-05-13 09:24:49 +02:00
|
|
|
* \brief Handle edge streams.
|
2016-10-15 02:08:51 +02:00
|
|
|
*
|
|
|
|
* An edge_connection_t is a subtype of a connection_t, and represents two
|
|
|
|
* critical concepts in Tor: a stream, and an edge connection. From the Tor
|
|
|
|
* protocol's point of view, a stream is a bi-directional channel that is
|
|
|
|
* multiplexed on a single circuit. Each stream on a circuit is identified
|
|
|
|
* with a separate 16-bit stream ID, local to the (circuit,exit) pair.
|
|
|
|
* Streams are created in response to client requests.
|
|
|
|
*
|
|
|
|
* An edge connection is one thing that can implement a stream: it is either a
|
|
|
|
* TCP application socket that has arrived via (e.g.) a SOCKS request, or an
|
|
|
|
* exit connection.
|
|
|
|
*
|
|
|
|
* Not every instance of edge_connection_t truly represents an edge connction,
|
|
|
|
* however. (Sorry!) We also create edge_connection_t objects for streams that
|
|
|
|
* we will not be handling with TCP. The types of these streams are:
|
|
|
|
* <ul>
|
|
|
|
* <li>DNS lookup streams, created on the client side in response to
|
|
|
|
* a UDP DNS request received on a DNSPort, or a RESOLVE command
|
|
|
|
* on a controller.
|
|
|
|
* <li>DNS lookup streams, created on the exit side in response to
|
|
|
|
* a RELAY_RESOLVE cell from a client.
|
|
|
|
* <li>Tunneled directory streams, created on the directory cache side
|
2017-02-09 17:48:11 +01:00
|
|
|
* in response to a RELAY_BEGIN_DIR cell. These streams attach directly
|
2016-10-15 02:08:51 +02:00
|
|
|
* to a dir_connection_t object without ever using TCP.
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
* This module handles general-purpose functionality having to do with
|
|
|
|
* edge_connection_t. On the client side, it accepts various types of
|
|
|
|
* application requests on SocksPorts, TransPorts, and NATDPorts, and
|
|
|
|
* creates streams appropriately.
|
|
|
|
*
|
|
|
|
* This module is also responsible for implementing stream isolation:
|
|
|
|
* ensuring that streams that should not be linkable to one another are
|
|
|
|
* kept to different circuits.
|
|
|
|
*
|
|
|
|
* On the exit side, this module handles the various stream-creating
|
|
|
|
* type of RELAY cells by launching appropriate outgoing connections,
|
|
|
|
* DNS requests, or directory connection objects.
|
|
|
|
*
|
|
|
|
* And for all edge connections, this module is responsible for handling
|
|
|
|
* incoming and outdoing data as it arrives or leaves in the relay.c
|
|
|
|
* module. (Outgoing data will be packaged in
|
|
|
|
* connection_edge_process_inbuf() as it calls
|
|
|
|
* connection_edge_package_raw_inbuf(); incoming data from RELAY_DATA
|
|
|
|
* cells is applied in connection_edge_process_relay_cell().)
|
2004-05-10 06:42:22 +02:00
|
|
|
**/
|
2012-10-22 17:28:37 +02:00
|
|
|
#define CONNECTION_EDGE_PRIVATE
|
2004-05-10 06:42:22 +02:00
|
|
|
|
2003-04-12 00:11:11 +02:00
|
|
|
#include "or.h"
|
2015-11-27 18:11:51 +01:00
|
|
|
|
|
|
|
#include "backtrace.h"
|
|
|
|
|
2012-10-28 21:13:58 +01:00
|
|
|
#include "addressmap.h"
|
2010-07-22 00:46:18 +02:00
|
|
|
#include "buffers.h"
|
2012-08-25 20:55:39 +02:00
|
|
|
#include "channel.h"
|
2013-10-31 19:33:34 +01:00
|
|
|
#include "circpathbias.h"
|
2010-07-22 09:46:23 +02:00
|
|
|
#include "circuitlist.h"
|
2010-07-22 10:03:40 +02:00
|
|
|
#include "circuituse.h"
|
2010-07-22 10:22:51 +02:00
|
|
|
#include "config.h"
|
2010-07-22 10:32:52 +02:00
|
|
|
#include "connection.h"
|
2010-07-22 10:43:02 +02:00
|
|
|
#include "connection_edge.h"
|
2010-07-22 10:50:34 +02:00
|
|
|
#include "connection_or.h"
|
2010-07-22 11:35:09 +02:00
|
|
|
#include "control.h"
|
2010-07-22 12:24:25 +02:00
|
|
|
#include "dns.h"
|
2010-07-21 12:26:18 +02:00
|
|
|
#include "dnsserv.h"
|
2016-07-14 06:04:02 +02:00
|
|
|
#include "directory.h"
|
2010-07-22 12:09:49 +02:00
|
|
|
#include "dirserv.h"
|
2010-07-22 12:30:46 +02:00
|
|
|
#include "hibernate.h"
|
2016-05-31 20:51:30 +02:00
|
|
|
#include "hs_common.h"
|
2010-07-23 19:58:06 +02:00
|
|
|
#include "main.h"
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
#include "nodelist.h"
|
2010-07-23 20:51:25 +02:00
|
|
|
#include "policies.h"
|
2010-07-23 21:08:30 +02:00
|
|
|
#include "reasons.h"
|
2010-07-23 21:53:11 +02:00
|
|
|
#include "relay.h"
|
2010-07-22 00:13:51 +02:00
|
|
|
#include "rendclient.h"
|
2010-07-21 17:52:54 +02:00
|
|
|
#include "rendcommon.h"
|
2010-07-22 00:30:17 +02:00
|
|
|
#include "rendservice.h"
|
2010-07-23 22:57:20 +02:00
|
|
|
#include "rephist.h"
|
2010-07-21 16:17:10 +02:00
|
|
|
#include "router.h"
|
2010-07-21 17:08:11 +02:00
|
|
|
#include "routerlist.h"
|
2012-09-13 18:46:39 +02:00
|
|
|
#include "routerset.h"
|
2013-01-19 04:37:16 +01:00
|
|
|
#include "circuitbuild.h"
|
2003-04-12 00:11:11 +02:00
|
|
|
|
2008-08-07 21:39:52 +02:00
|
|
|
#ifdef HAVE_LINUX_TYPES_H
|
|
|
|
#include <linux/types.h>
|
|
|
|
#endif
|
2006-08-10 11:01:46 +02:00
|
|
|
#ifdef HAVE_LINUX_NETFILTER_IPV4_H
|
|
|
|
#include <linux/netfilter_ipv4.h>
|
|
|
|
#define TRANS_NETFILTER
|
2014-12-23 16:51:33 +01:00
|
|
|
#define TRANS_NETFILTER_IPV4
|
2006-08-10 11:01:46 +02:00
|
|
|
#endif
|
|
|
|
|
2014-12-23 16:51:33 +01:00
|
|
|
#ifdef HAVE_LINUX_IF_H
|
|
|
|
#include <linux/if.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
|
|
|
|
#include <linux/netfilter_ipv6/ip6_tables.h>
|
2014-12-23 17:36:27 +01:00
|
|
|
#if defined(IP6T_SO_ORIGINAL_DST)
|
2014-12-23 16:51:33 +01:00
|
|
|
#define TRANS_NETFILTER
|
|
|
|
#define TRANS_NETFILTER_IPV6
|
|
|
|
#endif
|
2014-12-23 17:36:27 +01:00
|
|
|
#endif
|
2014-12-23 16:51:33 +01:00
|
|
|
|
2006-08-10 11:01:46 +02:00
|
|
|
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/pfvar.h>
|
|
|
|
#define TRANS_PF
|
|
|
|
#endif
|
|
|
|
|
2015-02-04 16:09:54 +01:00
|
|
|
#ifdef IP_TRANSPARENT
|
|
|
|
#define TRANS_TPROXY
|
|
|
|
#endif
|
|
|
|
|
2008-08-25 09:06:55 +02:00
|
|
|
#define SOCKS4_GRANTED 90
|
|
|
|
#define SOCKS4_REJECT 91
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
static int connection_ap_handshake_process_socks(entry_connection_t *conn);
|
|
|
|
static int connection_ap_process_natd(entry_connection_t *conn);
|
2007-05-13 11:25:06 +02:00
|
|
|
static int connection_exit_connect_dir(edge_connection_t *exitconn);
|
2011-07-20 18:55:42 +02:00
|
|
|
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
|
|
|
|
static int connection_ap_supports_optimistic_data(const entry_connection_t *);
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2005-03-27 06:55:13 +02:00
|
|
|
/** An AP stream has failed/finished. If it hasn't already sent back
|
|
|
|
* a socks reply, send one now (based on endreason). Also set
|
|
|
|
* has_sent_end to 1, and mark the conn.
|
|
|
|
*/
|
2014-04-02 19:38:50 +02:00
|
|
|
MOCK_IMPL(void,
|
|
|
|
connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason,
|
|
|
|
int line, const char *file))
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_t *base_conn = ENTRY_TO_CONN(conn);
|
2011-10-03 21:13:38 +02:00
|
|
|
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(base_conn->type == CONN_TYPE_AP);
|
|
|
|
ENTRY_TO_EDGE_CONN(conn)->edge_has_sent_end = 1; /* no circ yet */
|
2005-03-27 08:37:56 +02:00
|
|
|
|
2011-09-17 12:23:26 +02:00
|
|
|
/* If this is a rendezvous stream and it is failing without ever
|
|
|
|
* being attached to a circuit, assume that an attempt to connect to
|
|
|
|
* the destination hidden service has just ended.
|
|
|
|
*
|
2012-06-15 15:37:40 +02:00
|
|
|
* XXXX This condition doesn't limit to only streams failing
|
2011-09-17 12:23:26 +02:00
|
|
|
* without ever being attached. That sloppiness should be harmless,
|
|
|
|
* but we should fix it someday anyway. */
|
2011-10-03 21:13:38 +02:00
|
|
|
if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) &&
|
|
|
|
connection_edge_is_rendezvous_stream(edge_conn)) {
|
2015-04-27 22:21:47 +02:00
|
|
|
rend_client_note_connection_attempt_ended(edge_conn->rend_data);
|
2011-09-17 12:23:26 +02:00
|
|
|
}
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (base_conn->marked_for_close) {
|
2005-04-03 07:22:33 +02:00
|
|
|
/* This call will warn as appropriate. */
|
2012-10-12 18:22:13 +02:00
|
|
|
connection_mark_for_close_(base_conn, line, file);
|
2005-04-03 00:11:24 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-03-27 06:55:13 +02:00
|
|
|
if (!conn->socks_request->has_finished) {
|
2007-02-07 07:54:27 +01:00
|
|
|
if (endreason & END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED)
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_BUG,
|
2007-03-04 21:11:46 +01:00
|
|
|
"stream (marked at %s:%d) sending two socks replies?",
|
2006-02-13 10:02:35 +01:00
|
|
|
file, line);
|
2005-03-27 08:37:56 +02:00
|
|
|
|
2006-12-13 01:28:56 +01:00
|
|
|
if (SOCKS_COMMAND_IS_CONNECT(conn->socks_request->command))
|
2006-10-20 19:54:43 +02:00
|
|
|
connection_ap_handshake_socks_reply(conn, NULL, 0, endreason);
|
2007-02-12 04:01:36 +01:00
|
|
|
else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command))
|
2007-06-01 01:40:35 +02:00
|
|
|
connection_ap_handshake_socks_resolved(conn,
|
|
|
|
RESOLVED_TYPE_ERROR_TRANSIENT,
|
2007-07-10 19:14:51 +02:00
|
|
|
0, NULL, -1, -1);
|
2007-02-12 04:01:36 +01:00
|
|
|
else /* unknown or no handshake at all. send no response. */
|
|
|
|
conn->socks_request->has_finished = 1;
|
2005-03-27 06:55:13 +02:00
|
|
|
}
|
2005-03-27 08:37:56 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
connection_mark_and_flush_(base_conn, line, file);
|
2010-10-13 19:08:38 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason;
|
2005-03-27 06:55:13 +02:00
|
|
|
}
|
|
|
|
|
2004-11-21 11:14:57 +01:00
|
|
|
/** There was an EOF. Send an end and mark the connection for close.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_edge_reached_eof(edge_connection_t *conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2009-07-31 17:39:31 +02:00
|
|
|
if (connection_get_inbuf_len(TO_CONN(conn)) &&
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_state_is_open(TO_CONN(conn))) {
|
2004-11-21 12:30:33 +01:00
|
|
|
/* it still has stuff to process. don't let it die yet. */
|
|
|
|
return 0;
|
|
|
|
}
|
2012-11-02 19:22:21 +01:00
|
|
|
log_info(LD_EDGE,"conn (fd "TOR_SOCKET_T_FORMAT") reached eof. Closing.",
|
|
|
|
conn->base_.s);
|
2012-10-12 18:22:13 +02:00
|
|
|
if (!conn->base_.marked_for_close) {
|
2004-11-21 11:14:57 +01:00
|
|
|
/* only mark it if not already marked. it's possible to
|
|
|
|
* get the 'end' right around when the client hangs up on us. */
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end(conn, END_STREAM_REASON_DONE);
|
2012-10-12 18:22:13 +02:00
|
|
|
if (conn->base_.type == CONN_TYPE_AP) {
|
2011-07-20 18:55:42 +02:00
|
|
|
/* eof, so don't send a socks reply back */
|
|
|
|
if (EDGE_TO_ENTRY_CONN(conn)->socks_request)
|
|
|
|
EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1;
|
|
|
|
}
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
2004-11-21 11:14:57 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Handle new bytes on conn->inbuf based on state:
|
2004-05-10 06:42:22 +02:00
|
|
|
* - If it's waiting for socks info, try to read another step of the
|
|
|
|
* socks handshake out of conn->inbuf.
|
2006-08-10 11:01:37 +02:00
|
|
|
* - If it's waiting for the original destination, fetch it.
|
2004-05-10 06:42:22 +02:00
|
|
|
* - If it's open, then package more relay cells from the stream.
|
|
|
|
* - Else, leave the bytes on inbuf alone for now.
|
|
|
|
*
|
|
|
|
* Mark and return -1 if there was an unexpected error with the conn,
|
2004-04-01 00:02:13 +02:00
|
|
|
* else return 0.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(conn);
|
2003-04-12 00:11:11 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
switch (conn->base_.state) {
|
2003-04-12 00:11:11 +02:00
|
|
|
case AP_CONN_STATE_SOCKS_WAIT:
|
2011-09-08 02:26:58 +02:00
|
|
|
if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) {
|
2005-03-27 08:37:56 +02:00
|
|
|
/* already marked */
|
2003-10-21 10:37:07 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-11-14 01:06:31 +01:00
|
|
|
case AP_CONN_STATE_NATD_WAIT:
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_ap_process_natd(EDGE_TO_ENTRY_CONN(conn)) < 0) {
|
2006-11-14 01:06:31 +01:00
|
|
|
/* already marked */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2003-04-12 00:11:11 +02:00
|
|
|
case AP_CONN_STATE_OPEN:
|
|
|
|
case EXIT_CONN_STATE_OPEN:
|
2010-09-13 22:05:22 +02:00
|
|
|
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) {
|
2005-03-02 04:13:05 +01:00
|
|
|
/* (We already sent an end cell if possible) */
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
2003-10-21 10:37:07 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-04-12 00:11:11 +02:00
|
|
|
return 0;
|
2011-07-18 19:56:22 +02:00
|
|
|
case AP_CONN_STATE_CONNECT_WAIT:
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_ap_supports_optimistic_data(EDGE_TO_ENTRY_CONN(conn))) {
|
2011-07-18 19:56:22 +02:00
|
|
|
log_info(LD_EDGE,
|
|
|
|
"data from edge while in '%s' state. Sending it anyway. "
|
|
|
|
"package_partial=%d, buflen=%ld",
|
2012-10-12 18:22:13 +02:00
|
|
|
conn_state_to_string(conn->base_.type, conn->base_.state),
|
2011-08-09 11:34:21 +02:00
|
|
|
package_partial,
|
|
|
|
(long)connection_get_inbuf_len(TO_CONN(conn)));
|
2011-07-18 19:56:22 +02:00
|
|
|
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
|
|
|
|
/* (We already sent an end cell if possible) */
|
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Fall through if the connection is on a circuit without optimistic
|
|
|
|
* data support. */
|
2017-05-28 23:49:31 +02:00
|
|
|
/* Falls through. */
|
2003-04-12 00:11:11 +02:00
|
|
|
case EXIT_CONN_STATE_CONNECTING:
|
2004-04-05 02:47:48 +02:00
|
|
|
case AP_CONN_STATE_RENDDESC_WAIT:
|
2004-04-01 00:02:13 +02:00
|
|
|
case AP_CONN_STATE_CIRCUIT_WAIT:
|
2004-11-24 07:16:36 +01:00
|
|
|
case AP_CONN_STATE_RESOLVE_WAIT:
|
2005-03-23 06:32:06 +01:00
|
|
|
case AP_CONN_STATE_CONTROLLER_WAIT:
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_EDGE,
|
|
|
|
"data from edge while in '%s' state. Leaving it on buffer.",
|
2012-10-12 18:22:13 +02:00
|
|
|
conn_state_to_string(conn->base_.type, conn->base_.state));
|
2003-04-12 00:11:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2012-10-12 18:22:13 +02:00
|
|
|
log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state);
|
2005-04-26 20:52:16 +02:00
|
|
|
tor_fragile_assert();
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end(conn, END_STREAM_REASON_INTERNAL);
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
2004-01-20 10:21:46 +01:00
|
|
|
return -1;
|
2003-04-12 00:11:11 +02:00
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** This edge needs to be closed, because its circuit has closed.
|
|
|
|
* Mark it for close and return 0.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2008-07-23 17:58:30 +02:00
|
|
|
connection_edge_destroy(circid_t circ_id, edge_connection_t *conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2012-10-12 18:22:13 +02:00
|
|
|
if (!conn->base_.marked_for_close) {
|
2013-03-10 13:32:58 +01:00
|
|
|
log_info(LD_EDGE, "CircID %u: At an edge. Marking connection for close.",
|
|
|
|
(unsigned) circ_id);
|
2012-10-12 18:22:13 +02:00
|
|
|
if (conn->base_.type == CONN_TYPE_AP) {
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
|
|
|
|
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY);
|
2009-05-14 14:20:27 +02:00
|
|
|
control_event_stream_bandwidth(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED,
|
2008-07-23 16:07:26 +02:00
|
|
|
END_STREAM_REASON_DESTROY);
|
|
|
|
conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED;
|
2005-04-06 08:13:49 +02:00
|
|
|
} else {
|
2006-07-26 21:07:37 +02:00
|
|
|
/* closing the circuit, nothing to send an END to */
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->edge_has_sent_end = 1;
|
2006-10-20 19:54:48 +02:00
|
|
|
conn->end_reason = END_STREAM_REASON_DESTROY;
|
2007-02-07 07:54:22 +01:00
|
|
|
conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED;
|
2009-08-09 03:53:24 +02:00
|
|
|
connection_mark_and_flush(TO_CONN(conn));
|
2005-04-06 08:13:49 +02:00
|
|
|
}
|
2005-03-27 06:55:13 +02:00
|
|
|
}
|
2005-03-23 03:52:55 +01:00
|
|
|
conn->cpath_layer = NULL;
|
2005-04-06 08:13:49 +02:00
|
|
|
conn->on_circuit = NULL;
|
2004-02-29 01:11:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-12 21:30:42 +01:00
|
|
|
/** Send a raw end cell to the stream with ID <b>stream_id</b> out over the
|
|
|
|
* <b>circ</b> towards the hop identified with <b>cpath_layer</b>. If this
|
|
|
|
* is not a client connection, set the relay end cell's reason for closing
|
|
|
|
* as <b>reason</b> */
|
|
|
|
static int
|
|
|
|
relay_send_end_cell_from_edge(streamid_t stream_id, circuit_t *circ,
|
|
|
|
uint8_t reason, crypt_path_t *cpath_layer)
|
|
|
|
{
|
|
|
|
char payload[1];
|
|
|
|
|
|
|
|
if (CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) {
|
|
|
|
/* Never send the server an informative reason code; it doesn't need to
|
|
|
|
* know why the client stream is failing. */
|
|
|
|
reason = END_STREAM_REASON_MISC;
|
|
|
|
}
|
|
|
|
|
|
|
|
payload[0] = (char) reason;
|
|
|
|
|
|
|
|
return relay_send_command_from_edge(stream_id, circ, RELAY_COMMAND_END,
|
|
|
|
payload, 1, cpath_layer);
|
|
|
|
}
|
|
|
|
|
2017-01-10 14:35:15 +01:00
|
|
|
/* If the connection <b>conn</b> is attempting to connect to an external
|
|
|
|
* destination that is an hidden service and the reason is a connection
|
|
|
|
* refused or timeout, log it so the operator can take appropriate actions.
|
|
|
|
* The log statement is a rate limited warning. */
|
|
|
|
static void
|
|
|
|
warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason)
|
|
|
|
{
|
|
|
|
tor_assert(conn);
|
|
|
|
|
|
|
|
if (conn->base_.type == CONN_TYPE_EXIT &&
|
|
|
|
connection_edge_is_rendezvous_stream(conn) &&
|
|
|
|
(reason == END_STREAM_REASON_CONNECTREFUSED ||
|
|
|
|
reason == END_STREAM_REASON_TIMEOUT)) {
|
|
|
|
#define WARN_FAILED_HS_CONNECTION 300
|
|
|
|
static ratelim_t warn_limit = RATELIM_INIT(WARN_FAILED_HS_CONNECTION);
|
|
|
|
char *m;
|
|
|
|
if ((m = rate_limit_log(&warn_limit, approx_time()))) {
|
|
|
|
log_warn(LD_EDGE, "Onion service connection to %s failed (%s)",
|
|
|
|
(conn->base_.socket_family == AF_UNIX) ?
|
|
|
|
safe_str(conn->base_.address) :
|
|
|
|
safe_str(fmt_addrport(&conn->base_.addr, conn->base_.port)),
|
|
|
|
stream_end_reason_to_string(reason));
|
|
|
|
tor_free(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 21:30:42 +01:00
|
|
|
/** Send a relay end cell from stream <b>conn</b> down conn's circuit, and
|
|
|
|
* remember that we've done so. If this is not a client connection, set the
|
|
|
|
* relay end cell's reason for closing as <b>reason</b>.
|
2004-05-10 06:42:22 +02:00
|
|
|
*
|
|
|
|
* Return -1 if this function has already been called on this conn,
|
|
|
|
* else return 0.
|
|
|
|
*/
|
2004-05-12 23:12:33 +02:00
|
|
|
int
|
2008-12-12 21:30:42 +01:00
|
|
|
connection_edge_end(edge_connection_t *conn, uint8_t reason)
|
2004-05-12 23:12:33 +02:00
|
|
|
{
|
2005-09-12 23:42:59 +02:00
|
|
|
char payload[RELAY_PAYLOAD_SIZE];
|
2004-10-14 04:47:09 +02:00
|
|
|
size_t payload_len=1;
|
2003-10-22 09:55:44 +02:00
|
|
|
circuit_t *circ;
|
2009-01-05 15:14:57 +01:00
|
|
|
uint8_t control_reason = reason;
|
2003-10-21 10:37:07 +02:00
|
|
|
|
2008-12-17 15:59:28 +01:00
|
|
|
if (conn->edge_has_sent_end) {
|
2007-03-04 21:11:46 +01:00
|
|
|
log_warn(LD_BUG,"(Harmless.) Calling connection_edge_end (reason %d) "
|
2006-02-13 10:02:35 +01:00
|
|
|
"on an already ended stream?", reason);
|
2005-04-26 20:52:16 +02:00
|
|
|
tor_fragile_assert();
|
2003-12-14 09:32:14 +01:00
|
|
|
return -1;
|
2003-10-21 10:37:07 +02:00
|
|
|
}
|
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
if (conn->base_.marked_for_close) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_BUG,
|
2007-03-04 21:11:46 +01:00
|
|
|
"called on conn that's already marked for close at %s:%d.",
|
2012-10-12 18:22:13 +02:00
|
|
|
conn->base_.marked_for_close_file, conn->base_.marked_for_close);
|
2005-03-23 03:52:55 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-12 21:30:42 +01:00
|
|
|
circ = circuit_get_by_edge_conn(conn);
|
|
|
|
if (circ && CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) {
|
|
|
|
/* If this is a client circuit, don't send the server an informative
|
|
|
|
* reason code; it doesn't need to know why the client stream is
|
|
|
|
* failing. */
|
|
|
|
reason = END_STREAM_REASON_MISC;
|
|
|
|
}
|
|
|
|
|
|
|
|
payload[0] = (char)reason;
|
2005-09-13 00:05:17 +02:00
|
|
|
if (reason == END_STREAM_REASON_EXITPOLICY &&
|
|
|
|
!connection_edge_is_rendezvous_stream(conn)) {
|
2008-08-05 22:08:19 +02:00
|
|
|
int addrlen;
|
2012-10-12 18:22:13 +02:00
|
|
|
if (tor_addr_family(&conn->base_.addr) == AF_INET) {
|
|
|
|
set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr));
|
2008-08-05 22:08:19 +02:00
|
|
|
addrlen = 4;
|
|
|
|
} else {
|
2012-10-12 18:22:13 +02:00
|
|
|
memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16);
|
2008-08-05 22:08:19 +02:00
|
|
|
addrlen = 16;
|
|
|
|
}
|
|
|
|
set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl)));
|
|
|
|
payload_len += 4+addrlen;
|
2003-10-22 09:55:44 +02:00
|
|
|
}
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (circ && !circ->marked_for_close) {
|
2012-11-02 19:22:21 +01:00
|
|
|
log_debug(LD_EDGE,"Sending end on conn (fd "TOR_SOCKET_T_FORMAT").",
|
|
|
|
conn->base_.s);
|
2007-03-24 16:58:11 +01:00
|
|
|
connection_edge_send_command(conn, RELAY_COMMAND_END,
|
2007-03-24 16:57:51 +01:00
|
|
|
payload, payload_len);
|
2017-01-10 14:35:15 +01:00
|
|
|
/* We'll log warn if the connection was an hidden service and couldn't be
|
|
|
|
* made because the service wasn't available. */
|
|
|
|
warn_if_hs_unreachable(conn, control_reason);
|
2004-02-27 23:00:26 +01:00
|
|
|
} else {
|
2012-12-07 20:14:20 +01:00
|
|
|
log_debug(LD_EDGE,"No circ to send end on conn "
|
|
|
|
"(fd "TOR_SOCKET_T_FORMAT").",
|
2012-10-12 18:22:13 +02:00
|
|
|
conn->base_.s);
|
2003-10-21 10:37:07 +02:00
|
|
|
}
|
|
|
|
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->edge_has_sent_end = 1;
|
2009-01-05 15:14:57 +01:00
|
|
|
conn->end_reason = control_reason;
|
2003-12-14 09:32:14 +01:00
|
|
|
return 0;
|
2003-10-21 10:37:07 +02:00
|
|
|
}
|
|
|
|
|
2009-05-27 23:55:51 +02:00
|
|
|
/** An error has just occurred on an operation on an edge connection
|
2007-03-24 16:57:51 +01:00
|
|
|
* <b>conn</b>. Extract the errno; convert it to an end reason, and send an
|
|
|
|
* appropriate relay end cell to the other end of the connection's circuit.
|
2005-03-17 13:38:37 +01:00
|
|
|
**/
|
2005-03-01 23:42:31 +01:00
|
|
|
int
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end_errno(edge_connection_t *conn)
|
2005-03-01 23:42:31 +01:00
|
|
|
{
|
|
|
|
uint8_t reason;
|
|
|
|
tor_assert(conn);
|
2012-10-12 18:22:13 +02:00
|
|
|
reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s));
|
2007-03-24 16:57:51 +01:00
|
|
|
return connection_edge_end(conn, reason);
|
2005-03-01 23:42:31 +01:00
|
|
|
}
|
|
|
|
|
2011-03-14 22:48:45 +01:00
|
|
|
/** We just wrote some data to <b>conn</b>; act appropriately.
|
|
|
|
*
|
|
|
|
* (That is, if it's open, consider sending a stream-level sendme cell if we
|
|
|
|
* have just flushed enough.)
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
connection_edge_flushed_some(edge_connection_t *conn)
|
|
|
|
{
|
2012-10-12 18:22:13 +02:00
|
|
|
switch (conn->base_.state) {
|
2011-03-14 22:48:45 +01:00
|
|
|
case AP_CONN_STATE_OPEN:
|
|
|
|
case EXIT_CONN_STATE_OPEN:
|
|
|
|
connection_edge_consider_sending_sendme(conn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Connection <b>conn</b> has finished writing and has no bytes left on
|
|
|
|
* its outbuf.
|
|
|
|
*
|
|
|
|
* If it's in state 'open', stop writing, consider responding with a
|
|
|
|
* sendme, and return.
|
|
|
|
* Otherwise, stop writing and return.
|
|
|
|
*
|
|
|
|
* If <b>conn</b> is broken, mark it for close and return -1, else
|
|
|
|
* return 0.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_edge_finished_flushing(edge_connection_t *conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(conn);
|
2003-04-12 00:11:11 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
switch (conn->base_.state) {
|
2003-04-12 00:11:11 +02:00
|
|
|
case AP_CONN_STATE_OPEN:
|
|
|
|
case EXIT_CONN_STATE_OPEN:
|
2003-10-22 11:08:10 +02:00
|
|
|
connection_edge_consider_sending_sendme(conn);
|
2003-10-04 04:38:18 +02:00
|
|
|
return 0;
|
2003-10-04 03:37:01 +02:00
|
|
|
case AP_CONN_STATE_SOCKS_WAIT:
|
2006-11-14 01:06:31 +01:00
|
|
|
case AP_CONN_STATE_NATD_WAIT:
|
2004-04-05 02:47:48 +02:00
|
|
|
case AP_CONN_STATE_RENDDESC_WAIT:
|
2004-01-01 08:01:09 +01:00
|
|
|
case AP_CONN_STATE_CIRCUIT_WAIT:
|
2004-03-03 05:54:16 +01:00
|
|
|
case AP_CONN_STATE_CONNECT_WAIT:
|
2005-03-23 06:32:06 +01:00
|
|
|
case AP_CONN_STATE_CONTROLLER_WAIT:
|
2009-08-09 03:53:24 +02:00
|
|
|
case AP_CONN_STATE_RESOLVE_WAIT:
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0;
|
2003-04-12 00:11:11 +02:00
|
|
|
default:
|
2012-10-12 18:22:13 +02:00
|
|
|
log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state);
|
2005-04-26 20:52:16 +02:00
|
|
|
tor_fragile_assert();
|
2003-09-26 12:03:50 +02:00
|
|
|
return -1;
|
2003-04-12 00:11:11 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/** Longest size for the relay payload of a RELAY_CONNECTED cell that we're
|
|
|
|
* able to generate. */
|
|
|
|
/* 4 zero bytes; 1 type byte; 16 byte IPv6 address; 4 byte TTL. */
|
2012-11-14 16:48:58 +01:00
|
|
|
#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/** Set the buffer at <b>payload_out</b> -- which must have at least
|
|
|
|
* MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available -- to the body of a
|
|
|
|
* RELAY_CONNECTED cell indicating that we have connected to <b>addr</b>, and
|
|
|
|
* that the name resolution that led us to <b>addr</b> will be valid for
|
|
|
|
* <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on
|
|
|
|
* success. */
|
2013-06-06 23:58:28 +02:00
|
|
|
STATIC int
|
2012-11-14 16:48:58 +01:00
|
|
|
connected_cell_format_payload(uint8_t *payload_out,
|
|
|
|
const tor_addr_t *addr,
|
|
|
|
uint32_t ttl)
|
|
|
|
{
|
|
|
|
const sa_family_t family = tor_addr_family(addr);
|
|
|
|
int connected_payload_len;
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/* should be needless */
|
|
|
|
memset(payload_out, 0, MAX_CONNECTED_CELL_PAYLOAD_LEN);
|
|
|
|
|
2012-11-14 16:48:58 +01:00
|
|
|
if (family == AF_INET) {
|
|
|
|
set_uint32(payload_out, tor_addr_to_ipv4n(addr));
|
|
|
|
connected_payload_len = 4;
|
|
|
|
} else if (family == AF_INET6) {
|
|
|
|
set_uint32(payload_out, 0);
|
|
|
|
set_uint8(payload_out + 4, 6);
|
|
|
|
memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16);
|
|
|
|
connected_payload_len = 21;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
|
|
|
|
connected_payload_len += 4;
|
|
|
|
|
|
|
|
tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
|
|
|
|
|
|
|
|
return connected_payload_len;
|
|
|
|
}
|
|
|
|
|
2004-05-12 21:17:09 +02:00
|
|
|
/** Connected handler for exit connections: start writing pending
|
|
|
|
* data, deliver 'CONNECTED' relay cells as appropriate, and check
|
|
|
|
* any pending data that may have been received. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_edge_finished_connecting(edge_connection_t *edge_conn)
|
2004-05-12 21:17:09 +02:00
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_t *conn;
|
2004-05-12 21:17:09 +02:00
|
|
|
|
2006-07-26 21:07:26 +02:00
|
|
|
tor_assert(edge_conn);
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT);
|
2006-07-26 21:07:26 +02:00
|
|
|
conn = TO_CONN(edge_conn);
|
2004-05-12 21:17:09 +02:00
|
|
|
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
|
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
|
2009-12-15 23:23:36 +01:00
|
|
|
escaped_safe_str(conn->address), conn->port,
|
2012-10-07 05:30:58 +02:00
|
|
|
safe_str(fmt_and_decorate_addr(&conn->addr)));
|
2004-05-12 21:17:09 +02:00
|
|
|
|
2009-08-19 15:41:12 +02:00
|
|
|
rep_hist_note_exit_stream_opened(conn->port);
|
2009-06-24 19:51:45 +02:00
|
|
|
|
2004-05-12 21:17:09 +02:00
|
|
|
conn->state = EXIT_CONN_STATE_OPEN;
|
2016-08-02 19:15:10 +02:00
|
|
|
connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
|
2009-08-11 21:16:16 +02:00
|
|
|
if (connection_get_outbuf_len(conn)) /* in case there are any queued relay
|
2005-12-14 21:40:40 +01:00
|
|
|
* cells */
|
2004-05-12 21:17:09 +02:00
|
|
|
connection_start_writing(conn);
|
|
|
|
/* deliver a 'connected' relay cell back through the circuit. */
|
2006-07-26 21:07:26 +02:00
|
|
|
if (connection_edge_is_rendezvous_stream(edge_conn)) {
|
|
|
|
if (connection_edge_send_command(edge_conn,
|
2007-03-24 16:57:51 +01:00
|
|
|
RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
|
2004-05-12 21:17:09 +02:00
|
|
|
return 0; /* circuit is closed, don't continue */
|
|
|
|
} else {
|
2012-11-14 16:48:58 +01:00
|
|
|
uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
|
|
|
|
int connected_payload_len =
|
|
|
|
connected_cell_format_payload(connected_payload, &conn->addr,
|
|
|
|
edge_conn->address_ttl);
|
|
|
|
if (connected_payload_len < 0)
|
|
|
|
return -1;
|
|
|
|
|
2006-07-26 21:07:26 +02:00
|
|
|
if (connection_edge_send_command(edge_conn,
|
2012-11-14 16:48:58 +01:00
|
|
|
RELAY_COMMAND_CONNECTED,
|
|
|
|
(char*)connected_payload, connected_payload_len) < 0)
|
2004-05-12 21:17:09 +02:00
|
|
|
return 0; /* circuit is closed, don't continue */
|
|
|
|
}
|
2006-07-26 21:07:26 +02:00
|
|
|
tor_assert(edge_conn->package_window > 0);
|
2004-11-21 08:43:12 +01:00
|
|
|
/* in case the server has written anything */
|
2006-07-26 21:07:26 +02:00
|
|
|
return connection_edge_process_inbuf(edge_conn, 1);
|
2004-05-12 21:17:09 +02:00
|
|
|
}
|
|
|
|
|
2015-11-13 19:38:01 +01:00
|
|
|
/** A list of all the entry_connection_t * objects that are not marked
|
|
|
|
* for close, and are in AP_CONN_STATE_CIRCUIT_WAIT.
|
|
|
|
*
|
|
|
|
* (Right now, we check in several places to make sure that this list is
|
|
|
|
* correct. When it's incorrect, we'll fix it, and log a BUG message.)
|
|
|
|
*/
|
|
|
|
static smartlist_t *pending_entry_connections = NULL;
|
|
|
|
|
2015-11-17 14:49:30 +01:00
|
|
|
static int untried_pending_connections = 0;
|
|
|
|
|
2011-06-22 19:57:19 +02:00
|
|
|
/** Common code to connection_(ap|exit)_about_to_close. */
|
|
|
|
static void
|
|
|
|
connection_edge_about_to_close(edge_connection_t *edge_conn)
|
|
|
|
{
|
|
|
|
if (!edge_conn->edge_has_sent_end) {
|
|
|
|
connection_t *conn = TO_CONN(edge_conn);
|
|
|
|
log_warn(LD_BUG, "(Harmless.) Edge connection (marked at %s:%d) "
|
|
|
|
"hasn't sent end yet?",
|
|
|
|
conn->marked_for_close_file, conn->marked_for_close);
|
|
|
|
tor_fragile_assert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-05 01:51:00 +02:00
|
|
|
/** Called when we're about to finally unlink and free an AP (client)
|
2011-06-22 19:57:19 +02:00
|
|
|
* connection: perform necessary accounting and cleanup */
|
|
|
|
void
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_about_to_close(entry_connection_t *entry_conn)
|
2011-06-22 19:57:19 +02:00
|
|
|
{
|
|
|
|
circuit_t *circ;
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
|
|
|
|
connection_t *conn = ENTRY_TO_CONN(entry_conn);
|
2011-06-22 19:57:19 +02:00
|
|
|
|
2015-12-17 00:52:34 +01:00
|
|
|
connection_edge_about_to_close(edge_conn);
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (entry_conn->socks_request->has_finished == 0) {
|
2011-06-22 19:57:19 +02:00
|
|
|
/* since conn gets removed right after this function finishes,
|
|
|
|
* there's no point trying to send back a reply at this point. */
|
|
|
|
log_warn(LD_BUG,"Closing stream (marked at %s:%d) without sending"
|
|
|
|
" back a socks reply.",
|
|
|
|
conn->marked_for_close_file, conn->marked_for_close);
|
|
|
|
}
|
|
|
|
if (!edge_conn->end_reason) {
|
|
|
|
log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having"
|
|
|
|
" set end_reason.",
|
|
|
|
conn->marked_for_close_file, conn->marked_for_close);
|
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
if (entry_conn->dns_server_request) {
|
2011-06-22 19:57:19 +02:00
|
|
|
log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having"
|
|
|
|
" replied to DNS request.",
|
|
|
|
conn->marked_for_close_file, conn->marked_for_close);
|
2011-07-20 18:55:42 +02:00
|
|
|
dnsserv_reject_request(entry_conn);
|
2011-06-22 19:57:19 +02:00
|
|
|
}
|
2015-12-17 00:49:23 +01:00
|
|
|
|
|
|
|
if (TO_CONN(edge_conn)->state == AP_CONN_STATE_CIRCUIT_WAIT) {
|
|
|
|
smartlist_remove(pending_entry_connections, entry_conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
/* Check to make sure that this isn't in pending_entry_connections if it
|
|
|
|
* didn't actually belong there. */
|
2015-12-17 01:16:07 +01:00
|
|
|
if (TO_CONN(edge_conn)->type == CONN_TYPE_AP) {
|
|
|
|
connection_ap_warn_and_unmark_if_pending_circ(entry_conn,
|
|
|
|
"about_to_close");
|
2015-12-17 00:49:23 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-06-22 19:57:19 +02:00
|
|
|
control_event_stream_bandwidth(edge_conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED,
|
2011-06-22 19:57:19 +02:00
|
|
|
edge_conn->end_reason);
|
|
|
|
circ = circuit_get_by_edge_conn(edge_conn);
|
|
|
|
if (circ)
|
|
|
|
circuit_detach_stream(circ, edge_conn);
|
|
|
|
}
|
|
|
|
|
2012-06-05 01:51:00 +02:00
|
|
|
/** Called when we're about to finally unlink and free an exit
|
2011-06-22 19:57:19 +02:00
|
|
|
* connection: perform necessary accounting and cleanup */
|
|
|
|
void
|
|
|
|
connection_exit_about_to_close(edge_connection_t *edge_conn)
|
|
|
|
{
|
|
|
|
circuit_t *circ;
|
|
|
|
connection_t *conn = TO_CONN(edge_conn);
|
|
|
|
|
|
|
|
connection_edge_about_to_close(edge_conn);
|
|
|
|
|
|
|
|
circ = circuit_get_by_edge_conn(edge_conn);
|
|
|
|
if (circ)
|
|
|
|
circuit_detach_stream(circ, edge_conn);
|
|
|
|
if (conn->state == EXIT_CONN_STATE_RESOLVING) {
|
|
|
|
connection_dns_remove(edge_conn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-18 06:42:32 +02:00
|
|
|
/** Define a schedule for how long to wait between retrying
|
|
|
|
* application connections. Rather than waiting a fixed amount of
|
2006-12-20 10:43:28 +01:00
|
|
|
* time between each retry, we wait 10 seconds each for the first
|
2007-01-04 05:35:18 +01:00
|
|
|
* two tries, and 15 seconds for each retry after
|
2006-08-14 09:08:29 +02:00
|
|
|
* that. Hopefully this will improve the expected user experience. */
|
2006-07-18 06:42:32 +02:00
|
|
|
static int
|
2011-07-20 18:55:42 +02:00
|
|
|
compute_retry_timeout(entry_connection_t *conn)
|
2006-07-18 06:42:32 +02:00
|
|
|
{
|
2009-11-22 05:36:36 +01:00
|
|
|
int timeout = get_options()->CircuitStreamTimeout;
|
|
|
|
if (timeout) /* if our config options override the default, use them */
|
|
|
|
return timeout;
|
2006-12-20 10:43:28 +01:00
|
|
|
if (conn->num_socks_retries < 2) /* try 0 and try 1 */
|
2006-07-18 06:42:32 +02:00
|
|
|
return 10;
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
|
2005-12-14 21:40:40 +01:00
|
|
|
/** Find all general-purpose AP streams waiting for a response that sent their
|
2009-11-22 05:36:36 +01:00
|
|
|
* begin/resolve cell too long ago. Detach from their current circuit, and
|
2005-12-14 21:40:40 +01:00
|
|
|
* mark their current circuit as unsuitable for new streams. Then call
|
2004-05-10 06:42:22 +02:00
|
|
|
* connection_ap_handshake_attach_circuit() to attach to a new circuit (if
|
|
|
|
* available) or launch a new one.
|
|
|
|
*
|
2006-03-22 00:27:43 +01:00
|
|
|
* For rendezvous streams, simply give up after SocksTimeout seconds (with no
|
2004-05-10 06:42:22 +02:00
|
|
|
* retry attempt).
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
connection_ap_expire_beginning(void)
|
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
edge_connection_t *conn;
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *entry_conn;
|
2004-02-29 10:15:29 +01:00
|
|
|
circuit_t *circ;
|
2004-01-20 10:21:46 +01:00
|
|
|
time_t now = time(NULL);
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2006-04-09 23:36:37 +02:00
|
|
|
int severity;
|
2006-07-18 06:42:32 +02:00
|
|
|
int cutoff;
|
2009-02-13 05:11:14 +01:00
|
|
|
int seconds_idle, seconds_since_born;
|
2007-05-22 17:49:14 +02:00
|
|
|
smartlist_t *conns = get_connection_array();
|
2004-01-20 10:21:46 +01:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
|
|
|
|
if (base_conn->type != CONN_TYPE_AP || base_conn->marked_for_close)
|
2004-11-30 09:39:14 +01:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_conn = TO_ENTRY_CONN(base_conn);
|
|
|
|
conn = ENTRY_TO_EDGE_CONN(entry_conn);
|
2007-06-09 07:17:33 +02:00
|
|
|
/* if it's an internal linked connection, don't yell its status. */
|
2011-07-20 18:55:42 +02:00
|
|
|
severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port)
|
2006-07-26 21:07:37 +02:00
|
|
|
? LOG_INFO : LOG_NOTICE;
|
2011-07-20 18:55:42 +02:00
|
|
|
seconds_idle = (int)( now - base_conn->timestamp_lastread );
|
|
|
|
seconds_since_born = (int)( now - base_conn->timestamp_created );
|
2007-01-15 10:09:03 +01:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (base_conn->state == AP_CONN_STATE_OPEN)
|
2009-02-13 05:11:14 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We already consider SocksTimeout in
|
|
|
|
* connection_ap_handshake_attach_circuit(), but we need to consider
|
|
|
|
* it here too because controllers that put streams in controller_wait
|
|
|
|
* state never ask Tor to attach the circuit. */
|
2011-07-20 18:55:42 +02:00
|
|
|
if (AP_CONN_STATE_IS_UNATTACHED(base_conn->state)) {
|
2009-02-13 05:11:14 +01:00
|
|
|
if (seconds_since_born >= options->SocksTimeout) {
|
2007-02-11 03:15:42 +01:00
|
|
|
log_fn(severity, LD_APP,
|
|
|
|
"Tried for %d seconds to get a connection to %s:%d. "
|
|
|
|
"Giving up. (%s)",
|
2009-09-28 15:08:32 +02:00
|
|
|
seconds_since_born,
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(entry_conn->socks_request->address),
|
|
|
|
entry_conn->socks_request->port,
|
|
|
|
conn_state_to_string(CONN_TYPE_AP, base_conn->state));
|
|
|
|
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT);
|
2005-03-17 13:38:37 +01:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-02-12 04:01:36 +01:00
|
|
|
/* We're in state connect_wait or resolve_wait now -- waiting for a
|
|
|
|
* reply to our relay cell. See if we want to retry/give up. */
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
cutoff = compute_retry_timeout(entry_conn);
|
2007-01-15 10:09:03 +01:00
|
|
|
if (seconds_idle < cutoff)
|
2004-03-08 00:50:15 +01:00
|
|
|
continue;
|
2005-04-06 08:43:21 +02:00
|
|
|
circ = circuit_get_by_edge_conn(conn);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!circ) { /* it's vanished? */
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.",
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(entry_conn->socks_request->address));
|
|
|
|
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT);
|
2004-04-26 00:48:47 +02:00
|
|
|
continue;
|
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
2007-02-12 04:01:36 +01:00
|
|
|
if (seconds_idle >= options->SocksTimeout) {
|
2006-04-09 23:36:37 +02:00
|
|
|
log_fn(severity, LD_REND,
|
|
|
|
"Rend stream is %d seconds late. Giving up on address"
|
|
|
|
" '%s.onion'.",
|
2007-01-15 10:09:03 +01:00
|
|
|
seconds_idle,
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(entry_conn->socks_request->address));
|
2013-01-31 02:27:38 +01:00
|
|
|
/* Roll back path bias use state so that we probe the circuit
|
|
|
|
* if nothing else succeeds on it */
|
|
|
|
pathbias_mark_use_rollback(TO_ORIGIN_CIRCUIT(circ));
|
|
|
|
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT);
|
2004-04-06 00:43:01 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-26 19:43:40 +01:00
|
|
|
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
|
|
|
|
circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT &&
|
|
|
|
circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
|
2013-02-19 20:38:04 +01:00
|
|
|
log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. "
|
|
|
|
"The purpose on the circuit was %s; it was in state %s, "
|
|
|
|
"path_state %s.",
|
|
|
|
circuit_purpose_to_string(circ->purpose),
|
|
|
|
circuit_state_to_string(circ->state),
|
|
|
|
CIRCUIT_IS_ORIGIN(circ) ?
|
2013-02-19 21:08:54 +01:00
|
|
|
pathbias_state_to_string(TO_ORIGIN_CIRCUIT(circ)->path_state) :
|
|
|
|
"none");
|
2013-02-19 20:38:04 +01:00
|
|
|
}
|
2006-07-18 06:48:59 +02:00
|
|
|
log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
|
2011-05-16 03:58:46 +02:00
|
|
|
"We tried for %d seconds to connect to '%s' using exit %s."
|
2006-04-09 23:36:37 +02:00
|
|
|
" Retrying on a new circuit.",
|
2009-09-28 15:08:32 +02:00
|
|
|
seconds_idle,
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(entry_conn->socks_request->address),
|
2007-05-01 01:24:38 +02:00
|
|
|
conn->cpath_layer ?
|
2011-07-20 18:55:42 +02:00
|
|
|
extend_info_describe(conn->cpath_layer->extend_info):
|
|
|
|
"*unnamed*");
|
2004-12-04 04:26:35 +01:00
|
|
|
/* send an end down the circuit */
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
|
2004-12-04 04:26:35 +01:00
|
|
|
/* un-mark it as ending, since we're going to reuse it */
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->edge_has_sent_end = 0;
|
2006-10-20 19:54:48 +02:00
|
|
|
conn->end_reason = 0;
|
2013-02-20 00:29:17 +01:00
|
|
|
/* make us not try this circuit again, but allow
|
|
|
|
* current streams on it to survive if they can */
|
|
|
|
mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
|
|
|
|
|
2006-07-18 06:42:32 +02:00
|
|
|
/* give our stream another 'cutoff' seconds to try */
|
2012-10-12 18:22:13 +02:00
|
|
|
conn->base_.timestamp_lastread += cutoff;
|
2011-07-20 18:55:42 +02:00
|
|
|
if (entry_conn->num_socks_retries < 250) /* avoid overflow */
|
|
|
|
entry_conn->num_socks_retries++;
|
2005-03-14 04:12:59 +01:00
|
|
|
/* move it back into 'pending' state, and try to attach. */
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_ap_detach_retriable(entry_conn, TO_ORIGIN_CIRCUIT(circ),
|
2006-10-20 19:54:43 +02:00
|
|
|
END_STREAM_REASON_TIMEOUT)<0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
if (!base_conn->marked_for_close)
|
2011-09-08 02:26:58 +02:00
|
|
|
connection_mark_unattached_ap(entry_conn,
|
|
|
|
END_STREAM_REASON_CANT_ATTACH);
|
2004-12-04 04:26:35 +01:00
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
} SMARTLIST_FOREACH_END(base_conn);
|
2004-01-20 10:21:46 +01:00
|
|
|
}
|
|
|
|
|
2015-11-13 19:38:01 +01:00
|
|
|
/**
|
|
|
|
* As connection_ap_attach_pending, but first scans the entire connection
|
|
|
|
* array to see if any elements are missing.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_rescan_and_attach_pending(void)
|
2003-11-11 03:41:31 +01:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *entry_conn;
|
2007-05-22 17:49:14 +02:00
|
|
|
smartlist_t *conns = get_connection_array();
|
2015-11-13 19:38:01 +01:00
|
|
|
|
|
|
|
if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
|
|
|
|
pending_entry_connections = smartlist_new();
|
|
|
|
|
2012-07-17 15:33:38 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
2004-05-21 00:39:01 +02:00
|
|
|
if (conn->marked_for_close ||
|
|
|
|
conn->type != CONN_TYPE_AP ||
|
2003-12-03 10:50:02 +01:00
|
|
|
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
|
2003-11-16 06:33:45 +01:00
|
|
|
continue;
|
2015-11-13 19:38:01 +01:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_conn = TO_ENTRY_CONN(conn);
|
2015-12-16 14:24:54 +01:00
|
|
|
tor_assert(entry_conn);
|
2015-11-13 19:38:01 +01:00
|
|
|
if (! smartlist_contains(pending_entry_connections, entry_conn)) {
|
|
|
|
log_warn(LD_BUG, "Found a connection %p that was supposed to be "
|
|
|
|
"in pending_entry_connections, but wasn't. No worries; "
|
|
|
|
"adding it.",
|
|
|
|
pending_entry_connections);
|
2015-11-17 14:49:30 +01:00
|
|
|
untried_pending_connections = 1;
|
2015-11-27 18:54:57 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(entry_conn);
|
2015-11-13 19:38:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} SMARTLIST_FOREACH_END(conn);
|
|
|
|
|
2015-11-17 14:49:30 +01:00
|
|
|
connection_ap_attach_pending(1);
|
2015-11-13 19:38:01 +01:00
|
|
|
}
|
|
|
|
|
2015-12-16 14:37:40 +01:00
|
|
|
#ifdef DEBUGGING_17659
|
|
|
|
#define UNMARK() do { \
|
|
|
|
entry_conn->marked_pending_circ_line = 0; \
|
|
|
|
entry_conn->marked_pending_circ_file = 0; \
|
|
|
|
} while (0)
|
|
|
|
#else
|
|
|
|
#define UNMARK() do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
2015-11-13 19:38:01 +01:00
|
|
|
/** Tell any AP streams that are listed as waiting for a new circuit to try
|
2016-10-27 18:03:52 +02:00
|
|
|
* again. If there is an available circuit for a stream, attach it. Otherwise,
|
|
|
|
* launch a new circuit.
|
2015-11-17 14:49:30 +01:00
|
|
|
*
|
|
|
|
* If <b>retry</b> is false, only check the list if it contains at least one
|
|
|
|
* streams that we have not yet tried to attach to a circuit.
|
2015-11-13 19:38:01 +01:00
|
|
|
*/
|
|
|
|
void
|
2015-11-17 14:49:30 +01:00
|
|
|
connection_ap_attach_pending(int retry)
|
2015-11-13 19:38:01 +01:00
|
|
|
{
|
|
|
|
if (PREDICT_UNLIKELY(!pending_entry_connections)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-17 14:49:30 +01:00
|
|
|
if (untried_pending_connections == 0 && !retry)
|
|
|
|
return;
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Don't allow any modifications to list while we are iterating over
|
|
|
|
* it. We'll put streams back on this list if we can't attach them
|
|
|
|
* immediately. */
|
2015-12-17 18:28:40 +01:00
|
|
|
smartlist_t *pending = pending_entry_connections;
|
|
|
|
pending_entry_connections = smartlist_new();
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(pending,
|
2015-11-13 19:38:01 +01:00
|
|
|
entry_connection_t *, entry_conn) {
|
|
|
|
connection_t *conn = ENTRY_TO_CONN(entry_conn);
|
2015-12-16 14:24:54 +01:00
|
|
|
tor_assert(conn && entry_conn);
|
2015-11-13 19:38:01 +01:00
|
|
|
if (conn->marked_for_close) {
|
2015-12-16 14:37:40 +01:00
|
|
|
UNMARK();
|
2015-11-13 19:38:01 +01:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-27 17:21:51 +01:00
|
|
|
if (conn->magic != ENTRY_CONNECTION_MAGIC) {
|
2015-12-16 14:37:40 +01:00
|
|
|
log_warn(LD_BUG, "%p has impossible magic value %u.",
|
2015-11-27 17:21:51 +01:00
|
|
|
entry_conn, (unsigned)conn->magic);
|
2015-12-16 14:37:40 +01:00
|
|
|
UNMARK();
|
2015-11-27 17:21:51 +01:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-13 19:38:01 +01:00
|
|
|
if (conn->state != AP_CONN_STATE_CIRCUIT_WAIT) {
|
2015-11-26 18:44:12 +01:00
|
|
|
log_warn(LD_BUG, "%p is no longer in circuit_wait. Its current state "
|
|
|
|
"is %s. Why is it on pending_entry_connections?",
|
|
|
|
entry_conn,
|
|
|
|
conn_state_to_string(conn->type, conn->state));
|
2015-12-16 14:37:40 +01:00
|
|
|
UNMARK();
|
2015-11-13 19:38:01 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Okay, we're through the sanity checks. Try to handle this stream. */
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_ap_handshake_attach_circuit(entry_conn) < 0) {
|
|
|
|
if (!conn->marked_for_close)
|
|
|
|
connection_mark_unattached_ap(entry_conn,
|
2008-03-17 04:37:54 +01:00
|
|
|
END_STREAM_REASON_CANT_ATTACH);
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
2015-11-13 19:38:01 +01:00
|
|
|
|
2015-12-17 18:28:40 +01:00
|
|
|
if (! conn->marked_for_close &&
|
|
|
|
conn->type == CONN_TYPE_AP &&
|
|
|
|
conn->state == AP_CONN_STATE_CIRCUIT_WAIT) {
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Is it still waiting for a circuit? If so, we didn't attach it,
|
|
|
|
* so it's still pending. Put it back on the list.
|
|
|
|
*/
|
2015-12-17 18:28:40 +01:00
|
|
|
if (!smartlist_contains(pending_entry_connections, entry_conn)) {
|
|
|
|
smartlist_add(pending_entry_connections, entry_conn);
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-13 19:38:01 +01:00
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* If we got here, then we either closed the connection, or
|
|
|
|
* we attached it. */
|
2015-12-17 18:28:40 +01:00
|
|
|
UNMARK();
|
2015-11-13 19:38:01 +01:00
|
|
|
} SMARTLIST_FOREACH_END(entry_conn);
|
2015-11-17 14:49:30 +01:00
|
|
|
|
2015-12-17 18:28:40 +01:00
|
|
|
smartlist_free(pending);
|
2015-11-17 14:49:30 +01:00
|
|
|
untried_pending_connections = 0;
|
2015-11-13 19:38:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Mark <b>entry_conn</b> as needing to get attached to a circuit.
|
|
|
|
*
|
|
|
|
* And <b>entry_conn</b> must be in AP_CONN_STATE_CIRCUIT_WAIT,
|
|
|
|
* should not already be pending a circuit. The circuit will get
|
|
|
|
* launched or the connection will get attached the next time we
|
|
|
|
* call connection_ap_attach_pending().
|
|
|
|
*/
|
|
|
|
void
|
2015-11-26 18:44:12 +01:00
|
|
|
connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
|
|
|
|
const char *fname, int lineno)
|
2015-11-13 19:38:01 +01:00
|
|
|
{
|
|
|
|
connection_t *conn = ENTRY_TO_CONN(entry_conn);
|
|
|
|
tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
|
2015-11-27 18:54:57 +01:00
|
|
|
tor_assert(conn->magic == ENTRY_CONNECTION_MAGIC);
|
2015-11-13 19:38:01 +01:00
|
|
|
if (conn->marked_for_close)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
|
|
|
|
pending_entry_connections = smartlist_new();
|
|
|
|
|
|
|
|
if (PREDICT_UNLIKELY(smartlist_contains(pending_entry_connections,
|
|
|
|
entry_conn))) {
|
2015-11-26 18:44:12 +01:00
|
|
|
log_warn(LD_BUG, "What?? pending_entry_connections already contains %p! "
|
2015-12-16 14:37:40 +01:00
|
|
|
"(Called from %s:%d.)",
|
2015-11-26 18:44:12 +01:00
|
|
|
entry_conn, fname, lineno);
|
2015-12-16 14:37:40 +01:00
|
|
|
#ifdef DEBUGGING_17659
|
|
|
|
const char *f2 = entry_conn->marked_pending_circ_file;
|
|
|
|
log_warn(LD_BUG, "(Previously called from %s:%d.)\n",
|
|
|
|
f2 ? f2 : "<NULL>",
|
|
|
|
entry_conn->marked_pending_circ_line);
|
|
|
|
#endif
|
|
|
|
log_backtrace(LOG_WARN, LD_BUG, "To debug, this may help");
|
2015-11-13 19:38:01 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-16 14:37:40 +01:00
|
|
|
#ifdef DEBUGGING_17659
|
|
|
|
entry_conn->marked_pending_circ_line = (uint16_t) lineno;
|
|
|
|
entry_conn->marked_pending_circ_file = fname;
|
|
|
|
#endif
|
|
|
|
|
2015-11-17 14:49:30 +01:00
|
|
|
untried_pending_connections = 1;
|
2015-11-13 19:38:01 +01:00
|
|
|
smartlist_add(pending_entry_connections, entry_conn);
|
2016-10-31 05:23:53 +01:00
|
|
|
|
|
|
|
/* Work-around for bug 19969: we handle pending_entry_connections at
|
|
|
|
* the end of run_main_loop_once(), but in many cases that function will
|
|
|
|
* take a very long time, if ever, to finish its call to event_base_loop().
|
|
|
|
*
|
|
|
|
* So the fix is to tell it right now that it ought to finish its loop at
|
|
|
|
* its next available opportunity.
|
|
|
|
*/
|
|
|
|
tell_event_loop_to_finish();
|
2003-11-11 03:41:31 +01:00
|
|
|
}
|
|
|
|
|
2015-11-27 18:54:57 +01:00
|
|
|
/** Mark <b>entry_conn</b> as no longer waiting for a circuit. */
|
|
|
|
void
|
|
|
|
connection_ap_mark_as_non_pending_circuit(entry_connection_t *entry_conn)
|
|
|
|
{
|
|
|
|
if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
|
|
|
|
return;
|
2015-12-16 14:37:40 +01:00
|
|
|
UNMARK();
|
2015-11-27 18:54:57 +01:00
|
|
|
smartlist_remove(pending_entry_connections, entry_conn);
|
|
|
|
}
|
|
|
|
|
2016-03-26 15:11:45 +01:00
|
|
|
/* DOCDOC */
|
2015-12-17 01:16:07 +01:00
|
|
|
void
|
|
|
|
connection_ap_warn_and_unmark_if_pending_circ(entry_connection_t *entry_conn,
|
|
|
|
const char *where)
|
|
|
|
{
|
|
|
|
if (pending_entry_connections &&
|
|
|
|
smartlist_contains(pending_entry_connections, entry_conn)) {
|
|
|
|
log_warn(LD_BUG, "What was %p doing in pending_entry_connections in %s?",
|
|
|
|
entry_conn, where);
|
|
|
|
connection_ap_mark_as_non_pending_circuit(entry_conn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-27 23:55:51 +02:00
|
|
|
/** Tell any AP streams that are waiting for a one-hop tunnel to
|
2008-03-24 06:48:51 +01:00
|
|
|
* <b>failed_digest</b> that they are going to fail. */
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX We should get rid of this function, and instead attach
|
2009-05-27 23:55:51 +02:00
|
|
|
* one-hop streams to circ->p_streams so they get marked in
|
2008-03-24 06:48:51 +01:00
|
|
|
* circuit_mark_for_close like normal p_streams. */
|
|
|
|
void
|
2008-06-20 05:13:16 +02:00
|
|
|
connection_ap_fail_onehop(const char *failed_digest,
|
|
|
|
cpath_build_state_t *build_state)
|
2008-03-24 06:48:51 +01:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *entry_conn;
|
2008-03-24 06:48:51 +01:00
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
smartlist_t *conns = get_connection_array();
|
2008-08-05 22:08:19 +02:00
|
|
|
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
2008-03-24 06:48:51 +01:00
|
|
|
if (conn->marked_for_close ||
|
|
|
|
conn->type != CONN_TYPE_AP ||
|
|
|
|
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
|
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_conn = TO_ENTRY_CONN(conn);
|
|
|
|
if (!entry_conn->want_onehop)
|
2008-03-24 06:48:51 +01:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
if (hexdigest_to_digest(entry_conn->chosen_exit_name, digest) < 0 ||
|
2011-05-10 22:58:38 +02:00
|
|
|
tor_memneq(digest, failed_digest, DIGEST_LEN))
|
2008-06-20 05:13:16 +02:00
|
|
|
continue;
|
|
|
|
if (tor_digest_is_zero(digest)) {
|
|
|
|
/* we don't know the digest; have to compare addr:port */
|
2008-08-05 22:08:19 +02:00
|
|
|
tor_addr_t addr;
|
2008-06-20 05:13:16 +02:00
|
|
|
if (!build_state || !build_state->chosen_exit ||
|
2014-12-20 12:20:54 +01:00
|
|
|
!entry_conn->socks_request) {
|
2008-08-05 22:08:19 +02:00
|
|
|
continue;
|
2014-12-20 12:20:54 +01:00
|
|
|
}
|
2011-10-11 17:21:31 +02:00
|
|
|
if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 ||
|
2008-08-05 22:08:19 +02:00
|
|
|
!tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
|
2011-07-20 18:55:42 +02:00
|
|
|
build_state->chosen_exit->port != entry_conn->socks_request->port)
|
2008-06-20 05:13:16 +02:00
|
|
|
continue;
|
2008-03-24 06:48:51 +01:00
|
|
|
}
|
2009-05-27 23:55:51 +02:00
|
|
|
log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn "
|
2011-07-20 18:55:42 +02:00
|
|
|
"just failed.", entry_conn->chosen_exit_name,
|
|
|
|
entry_conn->socks_request->address);
|
|
|
|
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT);
|
2008-08-05 22:08:19 +02:00
|
|
|
} SMARTLIST_FOREACH_END(conn);
|
2008-03-24 06:48:51 +01:00
|
|
|
}
|
|
|
|
|
2006-10-01 08:41:13 +02:00
|
|
|
/** A circuit failed to finish on its last hop <b>info</b>. If there
|
|
|
|
* are any streams waiting with this exit node in mind, but they
|
|
|
|
* don't absolutely require it, make them give up on it.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
circuit_discard_optional_exit_enclaves(extend_info_t *info)
|
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *entry_conn;
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
const node_t *r1, *r2;
|
2006-10-01 08:41:13 +02:00
|
|
|
|
2007-05-22 17:49:14 +02:00
|
|
|
smartlist_t *conns = get_connection_array();
|
2008-12-17 15:59:28 +01:00
|
|
|
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
2006-10-01 08:41:13 +02:00
|
|
|
if (conn->marked_for_close ||
|
|
|
|
conn->type != CONN_TYPE_AP ||
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
|
2006-10-01 08:41:13 +02:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_conn = TO_ENTRY_CONN(conn);
|
|
|
|
if (!entry_conn->chosen_exit_optional &&
|
|
|
|
!entry_conn->chosen_exit_retries)
|
2008-12-17 15:59:28 +01:00
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
r1 = node_get_by_nickname(entry_conn->chosen_exit_name, 0);
|
2010-10-21 17:17:34 +02:00
|
|
|
r2 = node_get_by_id(info->identity_digest);
|
2008-02-21 10:00:54 +01:00
|
|
|
if (!r1 || !r2 || r1 != r2)
|
|
|
|
continue;
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(entry_conn->socks_request);
|
|
|
|
if (entry_conn->chosen_exit_optional) {
|
2006-10-01 08:41:13 +02:00
|
|
|
log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.",
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(entry_conn->chosen_exit_name),
|
|
|
|
escaped_safe_str_client(entry_conn->socks_request->address));
|
|
|
|
entry_conn->chosen_exit_optional = 0;
|
|
|
|
tor_free(entry_conn->chosen_exit_name); /* clears it */
|
2008-01-20 06:54:15 +01:00
|
|
|
/* if this port is dangerous, warn or reject it now that we don't
|
|
|
|
* think it'll be using an enclave. */
|
2011-07-20 18:55:42 +02:00
|
|
|
consider_plaintext_ports(entry_conn, entry_conn->socks_request->port);
|
2006-10-01 08:41:13 +02:00
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
if (entry_conn->chosen_exit_retries) {
|
|
|
|
if (--entry_conn->chosen_exit_retries == 0) { /* give up! */
|
|
|
|
clear_trackexithost_mappings(entry_conn->chosen_exit_name);
|
|
|
|
tor_free(entry_conn->chosen_exit_name); /* clears it */
|
2008-02-21 10:00:54 +01:00
|
|
|
/* if this port is dangerous, warn or reject it now that we don't
|
|
|
|
* think it'll be using an enclave. */
|
2011-07-20 18:55:42 +02:00
|
|
|
consider_plaintext_ports(entry_conn, entry_conn->socks_request->port);
|
2008-02-21 10:00:54 +01:00
|
|
|
}
|
|
|
|
}
|
2008-12-17 15:59:28 +01:00
|
|
|
} SMARTLIST_FOREACH_END(conn);
|
2006-10-01 08:41:13 +02:00
|
|
|
}
|
|
|
|
|
2005-03-17 13:38:37 +01:00
|
|
|
/** The AP connection <b>conn</b> has just failed while attaching or
|
|
|
|
* sending a BEGIN or resolving on <b>circ</b>, but another circuit
|
2006-12-10 09:04:50 +01:00
|
|
|
* might work. Detach the circuit, and either reattach it, launch a
|
2012-12-03 19:33:43 +01:00
|
|
|
* new circuit, tell the controller, or give up as appropriate.
|
2005-03-17 13:38:37 +01:00
|
|
|
*
|
|
|
|
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
|
2005-03-14 04:12:59 +01:00
|
|
|
*/
|
|
|
|
int
|
2011-09-08 02:26:58 +02:00
|
|
|
connection_ap_detach_retriable(entry_connection_t *conn,
|
|
|
|
origin_circuit_t *circ,
|
2006-10-20 19:54:43 +02:00
|
|
|
int reason)
|
2005-03-14 04:12:59 +01:00
|
|
|
{
|
2006-10-20 19:54:43 +02:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL);
|
2011-07-18 21:38:05 +02:00
|
|
|
|
2013-01-31 02:27:38 +01:00
|
|
|
/* Roll back path bias use state so that we probe the circuit
|
|
|
|
* if nothing else succeeds on it */
|
|
|
|
pathbias_mark_use_rollback(circ);
|
2013-01-19 04:29:17 +01:00
|
|
|
|
2011-07-18 21:38:05 +02:00
|
|
|
if (conn->pending_optimistic_data) {
|
2016-08-02 19:33:41 +02:00
|
|
|
buf_set_to_copy(&conn->sending_optimistic_data,
|
|
|
|
conn->pending_optimistic_data);
|
2011-07-18 21:38:05 +02:00
|
|
|
}
|
|
|
|
|
2008-05-27 22:26:40 +02:00
|
|
|
if (!get_options()->LeaveStreamsUnattached || conn->use_begindir) {
|
|
|
|
/* If we're attaching streams ourself, or if this connection is
|
|
|
|
* a tunneled directory connection, then just attach it. */
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
|
|
|
circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn));
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(conn);
|
2005-03-14 04:12:59 +01:00
|
|
|
} else {
|
2015-11-27 18:54:57 +01:00
|
|
|
CONNECTION_AP_EXPECT_NONPENDING(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
|
|
|
|
circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn));
|
2005-03-14 04:12:59 +01:00
|
|
|
}
|
2015-11-13 19:38:01 +01:00
|
|
|
return 0;
|
2005-03-14 04:12:59 +01:00
|
|
|
}
|
|
|
|
|
2008-01-20 06:54:15 +01:00
|
|
|
/** Check if <b>conn</b> is using a dangerous port. Then warn and/or
|
|
|
|
* reject depending on our config options. */
|
|
|
|
static int
|
2011-07-20 18:55:42 +02:00
|
|
|
consider_plaintext_ports(entry_connection_t *conn, uint16_t port)
|
2008-01-20 06:54:15 +01:00
|
|
|
{
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2012-04-11 18:59:57 +02:00
|
|
|
int reject = smartlist_contains_int_as_string(
|
|
|
|
options->RejectPlaintextPorts, port);
|
2008-01-20 06:54:15 +01:00
|
|
|
|
2012-04-11 18:50:50 +02:00
|
|
|
if (smartlist_contains_int_as_string(options->WarnPlaintextPorts, port)) {
|
2008-01-20 06:54:15 +01:00
|
|
|
log_warn(LD_APP, "Application request to port %d: this port is "
|
|
|
|
"commonly used for unencrypted protocols. Please make sure "
|
|
|
|
"you don't send anything you would mind the rest of the "
|
|
|
|
"Internet reading!%s", port, reject ? " Closing." : "");
|
|
|
|
control_event_client_status(LOG_WARN, "DANGEROUS_PORT PORT=%d RESULT=%s",
|
|
|
|
port, reject ? "REJECT" : "WARN");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reject) {
|
|
|
|
log_info(LD_APP, "Port %d listed in RejectPlaintextPorts. Closing.", port);
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-17 23:58:20 +01:00
|
|
|
/** How many times do we try connecting with an exit configured via
|
|
|
|
* TrackHostExits before concluding that it won't work any more and trying a
|
|
|
|
* different one? */
|
|
|
|
#define TRACKHOSTEXITS_RETRIES 5
|
|
|
|
|
2010-08-06 21:29:15 +02:00
|
|
|
/** Call connection_ap_handshake_rewrite_and_attach() unless a controller
|
2010-08-08 15:20:24 +02:00
|
|
|
* asked us to leave streams unattached. Return 0 in that case.
|
|
|
|
*
|
|
|
|
* See connection_ap_handshake_rewrite_and_attach()'s
|
|
|
|
* documentation for arguments and return value.
|
2010-08-06 21:29:15 +02:00
|
|
|
*/
|
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
|
2010-08-06 21:29:15 +02:00
|
|
|
origin_circuit_t *circ,
|
|
|
|
crypt_path_t *cpath)
|
|
|
|
{
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2010-08-06 21:29:15 +02:00
|
|
|
|
|
|
|
if (options->LeaveStreamsUnattached) {
|
2015-11-27 18:54:57 +01:00
|
|
|
CONNECTION_AP_EXPECT_NONPENDING(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
|
2010-08-06 21:29:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath);
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Try to perform any map-based rewriting of the target address in
|
|
|
|
* <b>conn</b>, filling in the fields of <b>out</b> as we go, and modifying
|
|
|
|
* conn->socks_request.address as appropriate.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2015-01-11 02:14:55 +01:00
|
|
|
STATIC void
|
2015-01-11 01:59:24 +01:00
|
|
|
connection_ap_handshake_rewrite(entry_connection_t *conn,
|
|
|
|
rewrite_result_t *out)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2006-02-03 12:37:19 +01:00
|
|
|
socks_request_t *socks = conn->socks_request;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2012-11-23 23:31:53 +01:00
|
|
|
tor_addr_t addr_tmp;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Initialize all the fields of 'out' to reasonable defaults */
|
2015-01-11 01:59:24 +01:00
|
|
|
out->automap = 0;
|
|
|
|
out->exit_source = ADDRMAPSRC_NONE;
|
|
|
|
out->map_expires = TIME_MAX;
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = 0;
|
|
|
|
out->should_close = 0;
|
2015-01-13 03:08:43 +01:00
|
|
|
out->orig_address[0] = 0;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* We convert all incoming addresses to lowercase. */
|
|
|
|
tor_strlower(socks->address);
|
|
|
|
/* Remember the original address. */
|
2015-01-11 01:59:24 +01:00
|
|
|
strlcpy(out->orig_address, socks->address, sizeof(out->orig_address));
|
2006-03-05 10:50:26 +01:00
|
|
|
log_debug(LD_APP,"Client asked for %s:%d",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(socks->address),
|
2006-02-13 10:02:35 +01:00
|
|
|
socks->port);
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Check for whether this is a .exit address. By default, those are
|
|
|
|
* disallowed when they're coming straight from the client, but you're
|
|
|
|
* allowed to have them in MapAddress commands and so forth. */
|
2012-05-11 23:00:41 +02:00
|
|
|
if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) {
|
|
|
|
log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to "
|
|
|
|
"security risks. Set AllowDotExit in your torrc to enable "
|
|
|
|
"it (at your own risk).");
|
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = END_STREAM_REASON_TORPROTOCOL;
|
|
|
|
out->should_close = 1;
|
|
|
|
return;
|
2012-05-11 23:00:41 +02:00
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Remember the original address so we can tell the user about what
|
|
|
|
* they actually said, not just what it turned into. */
|
2016-10-27 18:03:52 +02:00
|
|
|
/* XXX yes, this is the same as out->orig_address above. One is
|
|
|
|
* in the output, and one is in the connection. */
|
2015-01-18 21:10:35 +01:00
|
|
|
if (! conn->original_dest_address) {
|
|
|
|
/* Is the 'if' necessary here? XXXX */
|
2011-07-08 21:15:59 +02:00
|
|
|
conn->original_dest_address = tor_strdup(conn->socks_request->address);
|
2015-01-18 21:10:35 +01:00
|
|
|
}
|
2011-07-08 21:15:59 +02:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* First, apply MapAddress and MAPADDRESS mappings. We need to do
|
|
|
|
* these only for non-reverse lookups, since they don't exist for those.
|
2016-10-27 18:03:52 +02:00
|
|
|
* We also need to do this before we consider automapping, since we might
|
2015-01-18 21:10:35 +01:00
|
|
|
* e.g. resolve irc.oftc.net into irconionaddress.onion, at which point
|
|
|
|
* we'd need to automap it. */
|
2014-04-09 00:02:03 +02:00
|
|
|
if (socks->command != SOCKS_COMMAND_RESOLVE_PTR) {
|
|
|
|
const unsigned rewrite_flags = AMR_FLAG_USE_MAPADDRESS;
|
|
|
|
if (addressmap_rewrite(socks->address, sizeof(socks->address),
|
|
|
|
rewrite_flags, &out->map_expires, &out->exit_source)) {
|
|
|
|
control_event_stream_status(conn, STREAM_EVENT_REMAP,
|
|
|
|
REMAP_STREAM_SOURCE_CACHE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Now see if we need to create or return an existing Hostname->IP
|
|
|
|
* automapping. Automapping happens when we're asked to resolve a
|
|
|
|
* hostname, and AutomapHostsOnResolve is set, and the hostname has a
|
|
|
|
* suffix listed in AutomapHostsSuffixes. It's a handy feature
|
|
|
|
* that lets you have Tor assign e.g. IPv6 addresses for .onion
|
|
|
|
* names, and return them safely from DNSPort.
|
2015-01-18 21:10:35 +01:00
|
|
|
*/
|
2007-05-25 16:48:16 +02:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE &&
|
2012-11-23 23:31:53 +01:00
|
|
|
tor_addr_parse(&addr_tmp, socks->address)<0 &&
|
2012-11-25 20:31:35 +01:00
|
|
|
options->AutomapHostsOnResolve) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Check the suffix... */
|
2015-01-11 01:59:24 +01:00
|
|
|
out->automap = addressmap_address_should_automap(socks->address, options);
|
|
|
|
if (out->automap) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we get here, then we should apply an automapping for this. */
|
2007-05-25 16:48:16 +02:00
|
|
|
const char *new_addr;
|
2015-01-18 21:10:35 +01:00
|
|
|
/* We return an IPv4 address by default, or an IPv6 address if we
|
|
|
|
* are allowed to do so. */
|
2012-11-25 20:51:36 +01:00
|
|
|
int addr_type = RESOLVED_TYPE_IPV4;
|
|
|
|
if (conn->socks_request->socks_version != 4) {
|
2015-01-03 22:11:23 +01:00
|
|
|
if (!conn->entry_cfg.ipv4_traffic ||
|
|
|
|
(conn->entry_cfg.ipv6_traffic && conn->entry_cfg.prefer_ipv6) ||
|
|
|
|
conn->entry_cfg.prefer_ipv6_virtaddr)
|
2012-11-25 20:51:36 +01:00
|
|
|
addr_type = RESOLVED_TYPE_IPV6;
|
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Okay, register the target address as automapped, and find the new
|
|
|
|
* address we're supposed to give as a resolve answer. (Return a cached
|
|
|
|
* value if we've looked up this address before.
|
|
|
|
*/
|
2007-05-25 16:48:16 +02:00
|
|
|
new_addr = addressmap_register_virtual_address(
|
2012-11-25 20:51:36 +01:00
|
|
|
addr_type, tor_strdup(socks->address));
|
2011-01-05 22:36:48 +01:00
|
|
|
if (! new_addr) {
|
|
|
|
log_warn(LD_APP, "Unable to automap address %s",
|
|
|
|
escaped_safe_str(socks->address));
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = END_STREAM_REASON_INTERNAL;
|
|
|
|
out->should_close = 1;
|
|
|
|
return;
|
2011-01-05 22:36:48 +01:00
|
|
|
}
|
2007-05-25 16:48:16 +02:00
|
|
|
log_info(LD_APP, "Automapping %s to %s",
|
2009-12-15 23:23:36 +01:00
|
|
|
escaped_safe_str_client(socks->address),
|
|
|
|
safe_str_client(new_addr));
|
2007-05-25 16:48:16 +02:00
|
|
|
strlcpy(socks->address, new_addr, sizeof(socks->address));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Now handle reverse lookups, if they're in the cache. This doesn't
|
2016-10-27 18:03:52 +02:00
|
|
|
* happen too often, since client-side DNS caching is off by default,
|
|
|
|
* and very deprecated. */
|
2006-12-26 23:41:43 +01:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
|
2012-11-25 19:45:36 +01:00
|
|
|
unsigned rewrite_flags = 0;
|
2015-01-03 22:11:23 +01:00
|
|
|
if (conn->entry_cfg.use_cached_ipv4_answers)
|
2012-11-25 19:45:36 +01:00
|
|
|
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
|
2015-01-03 22:11:23 +01:00
|
|
|
if (conn->entry_cfg.use_cached_ipv6_answers)
|
2012-11-25 19:45:36 +01:00
|
|
|
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
|
|
|
|
|
2007-07-10 19:14:51 +02:00
|
|
|
if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
|
2015-01-11 01:59:24 +01:00
|
|
|
rewrite_flags, &out->map_expires)) {
|
2007-05-25 20:49:26 +02:00
|
|
|
char *result = tor_strdup(socks->address);
|
|
|
|
/* remember _what_ is supposed to have been resolved. */
|
2008-04-22 19:21:12 +02:00
|
|
|
tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]",
|
2015-01-11 01:59:24 +01:00
|
|
|
out->orig_address);
|
2006-12-26 23:41:43 +01:00
|
|
|
connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME,
|
2010-12-14 01:34:01 +01:00
|
|
|
strlen(result), (uint8_t*)result,
|
|
|
|
-1,
|
2015-01-11 01:59:24 +01:00
|
|
|
out->map_expires);
|
2015-01-18 20:19:26 +01:00
|
|
|
tor_free(result);
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = END_STREAM_REASON_DONE |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED;
|
|
|
|
out->should_close = 1;
|
|
|
|
return;
|
2006-12-26 23:41:43 +01:00
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
|
|
|
/* Hang on, did we find an answer saying that this is a reverse lookup for
|
2016-03-31 15:20:13 +02:00
|
|
|
* an internal address? If so, we should reject it if we're configured to
|
2015-01-18 21:10:35 +01:00
|
|
|
* do so. */
|
2007-08-27 17:33:58 +02:00
|
|
|
if (options->ClientDNSRejectInternalAddresses) {
|
2016-12-10 01:13:11 +01:00
|
|
|
/* Don't let clients try to do a reverse lookup on 10.0.0.1. */
|
2007-08-27 17:33:58 +02:00
|
|
|
tor_addr_t addr;
|
2008-03-18 19:51:34 +01:00
|
|
|
int ok;
|
2011-10-11 17:47:13 +02:00
|
|
|
ok = tor_addr_parse_PTR_name(
|
2008-12-19 19:52:00 +01:00
|
|
|
&addr, socks->address, AF_UNSPEC, 1);
|
|
|
|
if (ok == 1 && tor_addr_is_internal(&addr, 0)) {
|
2007-08-27 17:33:58 +02:00
|
|
|
connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR,
|
|
|
|
0, NULL, -1, TIME_MAX);
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = END_STREAM_REASON_SOCKSPROTOCOL |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED;
|
|
|
|
out->should_close = 1;
|
|
|
|
return;
|
2007-08-27 17:33:58 +02:00
|
|
|
}
|
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* If we didn't automap it before, then this is still the address that
|
|
|
|
* came straight from the user, mapped according to any
|
|
|
|
* MapAddress/MAPADDRESS commands. Now apply other mappings,
|
|
|
|
* including previously registered Automap entries (IP back to
|
|
|
|
* hostname), TrackHostExits entries, and client-side DNS cache
|
|
|
|
* entries (if they're turned on).
|
2015-01-18 21:10:35 +01:00
|
|
|
*/
|
2015-01-19 17:58:40 +01:00
|
|
|
if (socks->command != SOCKS_COMMAND_RESOLVE_PTR &&
|
2015-01-18 21:10:35 +01:00
|
|
|
!out->automap) {
|
2014-04-09 00:02:03 +02:00
|
|
|
unsigned rewrite_flags = AMR_FLAG_USE_AUTOMAP | AMR_FLAG_USE_TRACKEXIT;
|
|
|
|
addressmap_entry_source_t exit_source2;
|
2015-01-03 22:11:23 +01:00
|
|
|
if (conn->entry_cfg.use_cached_ipv4_answers)
|
2012-11-25 19:45:36 +01:00
|
|
|
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
|
2015-01-03 22:11:23 +01:00
|
|
|
if (conn->entry_cfg.use_cached_ipv6_answers)
|
2012-11-25 19:45:36 +01:00
|
|
|
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
|
2007-07-10 19:14:51 +02:00
|
|
|
if (addressmap_rewrite(socks->address, sizeof(socks->address),
|
2014-04-09 00:02:03 +02:00
|
|
|
rewrite_flags, &out->map_expires, &exit_source2)) {
|
2007-02-23 21:13:02 +01:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_REMAP,
|
|
|
|
REMAP_STREAM_SOURCE_CACHE);
|
2007-02-05 20:15:13 +01:00
|
|
|
}
|
2014-04-09 00:02:03 +02:00
|
|
|
if (out->exit_source == ADDRMAPSRC_NONE) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If it wasn't a .exit before, maybe it turned into a .exit. Remember
|
|
|
|
* the original source of a .exit. */
|
2014-04-09 00:02:03 +02:00
|
|
|
out->exit_source = exit_source2;
|
|
|
|
}
|
2006-12-26 23:41:43 +01:00
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Check to see whether we're about to use an address in the virtual
|
|
|
|
* range without actually having gotten it from an Automap. */
|
2015-01-11 01:59:24 +01:00
|
|
|
if (!out->automap && address_is_in_virtual_range(socks->address)) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* This address was probably handed out by
|
|
|
|
* client_dns_get_unmapped_address, but the mapping was discarded for some
|
|
|
|
* reason. Or the user typed in a virtual address range manually. We
|
|
|
|
* *don't* want to send the address through Tor; that's likely to fail,
|
|
|
|
* and may leak information.
|
2005-03-02 20:26:46 +01:00
|
|
|
*/
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(socks->address));
|
2015-01-11 02:07:35 +01:00
|
|
|
out->end_reason = END_STREAM_REASON_INTERNAL;
|
|
|
|
out->should_close = 1;
|
|
|
|
return;
|
2005-03-02 20:26:46 +01:00
|
|
|
}
|
2015-01-11 01:59:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Connection <b>conn</b> just finished its socks handshake, or the
|
|
|
|
* controller asked us to take care of it. If <b>circ</b> is defined,
|
|
|
|
* then that's where we'll want to attach it. Otherwise we have to
|
|
|
|
* figure it out ourselves.
|
|
|
|
*
|
|
|
|
* First, parse whether it's a .exit address, remap it, and so on. Then
|
|
|
|
* if it's for a general circuit, try to attach it to a circuit (or launch
|
|
|
|
* one as needed), else if it's for a rendezvous circuit, fetch a
|
|
|
|
* rendezvous descriptor first (or attach/launch a circuit if the
|
|
|
|
* rendezvous descriptor is already here and fresh enough).
|
|
|
|
*
|
|
|
|
* The stream will exit from the hop
|
|
|
|
* indicated by <b>cpath</b>, or from the last hop in circ's cpath if
|
|
|
|
* <b>cpath</b> is NULL.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
|
|
|
|
origin_circuit_t *circ,
|
|
|
|
crypt_path_t *cpath)
|
|
|
|
{
|
|
|
|
socks_request_t *socks = conn->socks_request;
|
|
|
|
const or_options_t *options = get_options();
|
|
|
|
connection_t *base_conn = ENTRY_TO_CONN(conn);
|
|
|
|
time_t now = time(NULL);
|
|
|
|
rewrite_result_t rr;
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* First we'll do the rewrite part. Let's see if we get a reasonable
|
|
|
|
* answer.
|
|
|
|
*/
|
2015-01-11 01:59:24 +01:00
|
|
|
memset(&rr, 0, sizeof(rr));
|
2015-01-11 02:07:35 +01:00
|
|
|
connection_ap_handshake_rewrite(conn,&rr);
|
|
|
|
|
|
|
|
if (rr.should_close) {
|
2016-10-27 18:03:52 +02:00
|
|
|
/* connection_ap_handshake_rewrite told us to close the connection:
|
2015-01-18 21:10:35 +01:00
|
|
|
* either because it sent back an answer, or because it sent back an
|
|
|
|
* error */
|
2015-01-11 02:07:35 +01:00
|
|
|
connection_mark_unattached_ap(conn, rr.end_reason);
|
2015-01-18 21:10:35 +01:00
|
|
|
if (END_STREAM_REASON_DONE == (rr.end_reason & END_STREAM_REASON_MASK))
|
2015-01-11 02:07:35 +01:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
2005-03-02 20:26:46 +01:00
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
const time_t map_expires = rr.map_expires;
|
|
|
|
const int automap = rr.automap;
|
|
|
|
const addressmap_entry_source_t exit_source = rr.exit_source;
|
2015-01-11 01:59:24 +01:00
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Now, we parse the address to see if it's an .onion or .exit or
|
|
|
|
* other special address.
|
2004-11-29 09:34:54 +01:00
|
|
|
*/
|
2015-01-18 21:10:35 +01:00
|
|
|
const hostname_type_t addresstype = parse_extended_hostname(socks->address);
|
2004-11-29 09:34:54 +01:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Now see whether the hostname is bogus. This could happen because of an
|
|
|
|
* onion hostname whose format we don't recognize. */
|
2006-02-03 12:37:19 +01:00
|
|
|
if (addresstype == BAD_HOSTNAME) {
|
2007-01-19 22:25:32 +01:00
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
2005-06-07 20:01:46 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If this is a .exit hostname, strip off the .name.exit part, and
|
2016-10-27 18:03:52 +02:00
|
|
|
* see whether we're willing to connect there, and and otherwise handle the
|
|
|
|
* .exit address.
|
2015-01-18 21:10:35 +01:00
|
|
|
*
|
|
|
|
* We'll set chosen_exit_name and/or close the connection as appropriate.
|
|
|
|
*/
|
2004-11-30 04:44:10 +01:00
|
|
|
if (addresstype == EXIT_HOSTNAME) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If StrictNodes is not set, then .exit overrides ExcludeNodes but
|
|
|
|
* not ExcludeExitNodes. */
|
2011-04-03 23:08:59 +02:00
|
|
|
routerset_t *excludeset = options->StrictNodes ?
|
2012-10-12 18:22:13 +02:00
|
|
|
options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes;
|
2015-01-18 21:10:35 +01:00
|
|
|
const node_t *node = NULL;
|
2011-04-03 23:08:59 +02:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If this .exit was added by an AUTOMAP, then it came straight from
|
2016-10-27 18:03:52 +02:00
|
|
|
* a user. Make sure that options->AllowDotExit permits that! */
|
2012-05-11 23:00:41 +02:00
|
|
|
if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) {
|
|
|
|
/* Whoops; this one is stale. It must have gotten added earlier,
|
|
|
|
* when AllowDotExit was on. */
|
|
|
|
log_warn(LD_APP,"Stale automapped address for '%s.exit', with "
|
|
|
|
"AllowDotExit disabled. Refusing.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Double-check to make sure there are no .exits coming from
|
|
|
|
* impossible/weird sources. */
|
2012-05-11 23:00:41 +02:00
|
|
|
if (exit_source == ADDRMAPSRC_DNS ||
|
|
|
|
(exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) {
|
|
|
|
/* It shouldn't be possible to get a .exit address from any of these
|
|
|
|
* sources. */
|
2012-06-12 03:50:52 +02:00
|
|
|
log_warn(LD_BUG,"Address '%s.exit', with impossible source for the "
|
|
|
|
".exit part. Refusing.",
|
2012-05-11 23:00:41 +02:00
|
|
|
safe_str_client(socks->address));
|
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
2016-10-27 18:03:52 +02:00
|
|
|
|
|
|
|
/* Now, find the character before the .(name) part.
|
|
|
|
* (The ".exit" part got stripped off by "parse_extended_hostname").
|
|
|
|
*
|
|
|
|
* We're going to put the exit name into conn->chosen_exit_name, and
|
|
|
|
* look up a node correspondingly. */
|
2015-01-18 21:10:35 +01:00
|
|
|
char *s = strrchr(socks->address,'.');
|
2005-05-11 06:14:17 +02:00
|
|
|
if (s) {
|
2011-04-03 23:08:59 +02:00
|
|
|
/* The address was of the form "(stuff).(name).exit */
|
2005-05-11 06:14:17 +02:00
|
|
|
if (s[1] != '\0') {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Looks like a real .exit one. */
|
2005-05-11 06:14:17 +02:00
|
|
|
conn->chosen_exit_name = tor_strdup(s+1);
|
2011-04-27 20:36:30 +02:00
|
|
|
node = node_get_by_nickname(conn->chosen_exit_name, 1);
|
2012-05-11 23:00:41 +02:00
|
|
|
|
|
|
|
if (exit_source == ADDRMAPSRC_TRACKEXIT) {
|
|
|
|
/* We 5 tries before it expires the addressmap */
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
|
2012-05-11 23:00:41 +02:00
|
|
|
}
|
2005-05-11 06:14:17 +02:00
|
|
|
*s = 0;
|
|
|
|
} else {
|
2011-04-03 23:08:59 +02:00
|
|
|
/* Oops, the address was (stuff)..exit. That's not okay. */
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(socks->address));
|
2007-01-19 22:25:32 +01:00
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
2005-05-11 06:14:17 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
2005-05-11 00:12:48 +02:00
|
|
|
} else {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* It looks like they just asked for "foo.exit". That's a special
|
|
|
|
* form that means (foo's address).foo.exit. */
|
2011-04-27 20:36:30 +02:00
|
|
|
|
2005-12-06 22:03:48 +01:00
|
|
|
conn->chosen_exit_name = tor_strdup(socks->address);
|
2011-04-27 20:36:30 +02:00
|
|
|
node = node_get_by_nickname(conn->chosen_exit_name, 1);
|
|
|
|
if (node) {
|
2011-04-03 23:08:59 +02:00
|
|
|
*socks->address = 0;
|
2011-04-27 20:36:30 +02:00
|
|
|
node_get_address_string(node, socks->address, sizeof(socks->address));
|
2005-05-11 00:12:48 +02:00
|
|
|
}
|
2004-11-29 09:34:54 +01:00
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2011-04-03 23:08:59 +02:00
|
|
|
/* Now make sure that the chosen exit exists... */
|
2011-04-27 20:36:30 +02:00
|
|
|
if (!node) {
|
2011-04-03 23:08:59 +02:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"Unrecognized relay in exit address '%s.exit'. Refusing.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* ...and make sure that it isn't excluded. */
|
2011-04-27 20:36:30 +02:00
|
|
|
if (routerset_contains_node(excludeset, node)) {
|
2011-04-03 23:08:59 +02:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"Excluded relay in exit address '%s.exit'. Refusing.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX-1090 Should we also allow foo.bar.exit if ExitNodes is set and
|
2011-04-03 23:08:59 +02:00
|
|
|
Bar is not listed in it? I say yes, but our revised manpage branch
|
|
|
|
implies no. */
|
2004-11-29 09:34:54 +01:00
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Now, we handle everything that isn't a .onion address. */
|
2004-11-30 04:44:10 +01:00
|
|
|
if (addresstype != ONION_HOSTNAME) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Not a hidden-service request. It's either a hostname or an IP,
|
2016-10-27 18:03:52 +02:00
|
|
|
* possibly with a .exit that we stripped off. We're going to check
|
|
|
|
* if we're allowed to connect/resolve there, and then launch the
|
|
|
|
* appropriate request. */
|
2015-01-18 21:10:35 +01:00
|
|
|
|
|
|
|
/* Check for funny characters in the address. */
|
2007-01-11 17:02:39 +01:00
|
|
|
if (address_is_invalid_destination(socks->address, 1)) {
|
2007-01-19 22:25:32 +01:00
|
|
|
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
|
|
|
escaped(socks->address));
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"Destination '%s' seems to be an invalid hostname. Failing.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(socks->address));
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
2005-02-01 13:19:44 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-19 15:09:25 +01:00
|
|
|
#ifdef ENABLE_TOR2WEB_MODE
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we're running in Tor2webMode, we don't allow anything BUT .onion
|
|
|
|
* addresses. */
|
2011-05-31 16:05:40 +02:00
|
|
|
if (options->Tor2webMode) {
|
2016-03-31 15:21:02 +02:00
|
|
|
log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname "
|
|
|
|
"or IP address %s because tor2web mode is enabled.",
|
2011-05-31 16:05:40 +02:00
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-19 15:09:25 +01:00
|
|
|
#endif
|
2011-05-31 16:05:40 +02:00
|
|
|
|
2016-03-31 15:22:17 +02:00
|
|
|
/* socks->address is a non-onion hostname or IP address.
|
|
|
|
* If we can't do any non-onion requests, refuse the connection.
|
|
|
|
* If we have a hostname but can't do DNS, refuse the connection.
|
|
|
|
* If we have an IP address, but we can't use that address family,
|
|
|
|
* refuse the connection.
|
|
|
|
*
|
|
|
|
* If we can do DNS requests, and we can use at least one address family,
|
|
|
|
* then we have to resolve the address first. Then we'll know if it
|
|
|
|
* resolves to a usable address family. */
|
|
|
|
|
|
|
|
/* First, check if all non-onion traffic is disabled */
|
|
|
|
if (!conn->entry_cfg.dns_request && !conn->entry_cfg.ipv4_traffic
|
|
|
|
&& !conn->entry_cfg.ipv6_traffic) {
|
|
|
|
log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname "
|
|
|
|
"or IP address %s because Port has OnionTrafficOnly set (or "
|
|
|
|
"NoDNSRequest, NoIPv4Traffic, and NoIPv6Traffic).",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then check if we have a hostname or IP address, and whether DNS or
|
2016-10-27 18:03:52 +02:00
|
|
|
* the IP address family are permitted. Reject if not. */
|
2016-03-31 15:22:17 +02:00
|
|
|
tor_addr_t dummy_addr;
|
|
|
|
int socks_family = tor_addr_parse(&dummy_addr, socks->address);
|
|
|
|
/* family will be -1 for a non-onion hostname that's not an IP */
|
2016-10-28 21:33:12 +02:00
|
|
|
if (socks_family == -1) {
|
|
|
|
if (!conn->entry_cfg.dns_request) {
|
|
|
|
log_warn(LD_APP, "Refusing to connect to hostname %s "
|
|
|
|
"because Port has NoDNSRequest set.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (socks_family == AF_INET) {
|
|
|
|
if (!conn->entry_cfg.ipv4_traffic) {
|
|
|
|
log_warn(LD_APP, "Refusing to connect to IPv4 address %s because "
|
|
|
|
"Port has NoIPv4Traffic set.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (socks_family == AF_INET6) {
|
|
|
|
if (!conn->entry_cfg.ipv6_traffic) {
|
|
|
|
log_warn(LD_APP, "Refusing to connect to IPv6 address %s because "
|
|
|
|
"Port has NoIPv6Traffic set.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-10-27 18:03:52 +02:00
|
|
|
} else {
|
|
|
|
tor_assert_nonfatal_unreached_once();
|
2016-03-31 15:22:17 +02:00
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* See if this is a hostname lookup that we can answer immediately.
|
|
|
|
* (For example, an attempt to look up the IP address for an IP address.)
|
|
|
|
*/
|
2006-09-22 02:44:07 +02:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE) {
|
2013-12-22 14:38:36 +01:00
|
|
|
tor_addr_t answer;
|
2004-12-05 13:47:46 +01:00
|
|
|
/* Reply to resolves immediately if we can. */
|
2013-12-22 14:38:36 +01:00
|
|
|
if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */
|
2007-05-25 20:22:43 +02:00
|
|
|
/* remember _what_ is supposed to have been resolved. */
|
2015-01-11 01:59:24 +01:00
|
|
|
strlcpy(socks->address, rr.orig_address, sizeof(socks->address));
|
2013-12-22 14:38:36 +01:00
|
|
|
connection_ap_handshake_socks_resolved_addr(conn, &answer, -1,
|
|
|
|
map_expires);
|
2005-12-14 21:40:40 +01:00
|
|
|
connection_mark_unattached_ap(conn,
|
2007-02-07 07:54:27 +01:00
|
|
|
END_STREAM_REASON_DONE |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
|
2004-12-05 13:47:46 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
2008-02-19 22:30:24 +01:00
|
|
|
rep_hist_note_used_resolve(now); /* help predict this next time */
|
2016-11-14 15:16:57 +01:00
|
|
|
} else if (socks->command == SOCKS_COMMAND_CONNECT) {
|
|
|
|
/* Now see if this is a connect request that we can reject immediately */
|
2016-10-27 18:03:52 +02:00
|
|
|
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Don't allow connections to port 0. */
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
if (socks->port == 0) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_notice(LD_APP,"Application asked to connect to port 0. Refusing.");
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
Introduce a notion of 'internal' circs, which are chosen without regard
to the exit policy of the last hop. Intro and rendezvous circs must
be internal circs, to avoid leaking information. Resolve and connect
streams can use internal circs if they want.
New circuit pooling algorithm: make sure to have enough circs around
to satisfy any predicted ports, and also make sure to have 2 internal
circs around if we've required internal circs lately (with high uptime
if we've seen that lately).
Split NewCircuitPeriod config option into NewCircuitPeriod (30 secs),
which describes how often we retry making new circuits if current ones
are dirty, and MaxCircuitDirtiness (10 mins), which describes how long
we're willing to make use of an already-dirty circuit.
Once rendezvous circuits are established, keep using the same circuit as
long as you attach a new stream to it at least every 10 minutes. (So web
browsing doesn't require you to build new rend circs every 30 seconds.)
Cannibalize GENERAL circs to be C_REND, C_INTRO, S_INTRO, and S_REND
circ as necessary, if there are any completed ones lying around when
we try to launch one.
Re-instate the ifdef's to use version-0 style introduce cells, since
there was yet another bug in handling version-1 style. We'll try switching
over again after 0.0.9 is obsolete.
Bugfix: when choosing an exit node for a new non-internal circ, don't take
into account whether it'll be useful for any pending x.onion addresses --
it won't.
Bugfix: we weren't actually publishing the hidden service descriptor when
it became dirty. So we only published it every 20 minutes or so, which
means when you first start your Tor, the hidden service will seem broken.
svn:r3360
2005-01-17 19:13:09 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
/* You can't make connections to internal addresses, by default.
|
2016-12-18 10:06:02 +01:00
|
|
|
* Exceptions are begindir requests (where the address is meaningless),
|
2015-01-18 21:10:35 +01:00
|
|
|
* or cases where you've hand-configured a particular exit, thereby
|
|
|
|
* making the local address meaningful. */
|
2011-01-26 17:35:24 +01:00
|
|
|
if (options->ClientRejectInternalAddresses &&
|
|
|
|
!conn->use_begindir && !conn->chosen_exit_name && !circ) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we reach this point then we don't want to allow internal
|
|
|
|
* addresses. Check if we got one. */
|
2011-01-26 02:39:44 +01:00
|
|
|
tor_addr_t addr;
|
2012-03-28 09:19:00 +02:00
|
|
|
if (tor_addr_hostname_is_local(socks->address) ||
|
|
|
|
(tor_addr_parse(&addr, socks->address) >= 0 &&
|
|
|
|
tor_addr_is_internal(&addr, 0))) {
|
2011-01-26 02:39:44 +01:00
|
|
|
/* If this is an explicit private address with no chosen exit node,
|
|
|
|
* then we really don't want to try to connect to it. That's
|
|
|
|
* probably an error. */
|
|
|
|
if (conn->is_transparent_ap) {
|
2012-06-05 06:49:18 +02:00
|
|
|
#define WARN_INTRVL_LOOP 300
|
|
|
|
static ratelim_t loop_warn_limit = RATELIM_INIT(WARN_INTRVL_LOOP);
|
2012-03-28 09:06:25 +02:00
|
|
|
char *m;
|
|
|
|
if ((m = rate_limit_log(&loop_warn_limit, approx_time()))) {
|
|
|
|
log_warn(LD_NET,
|
|
|
|
"Rejecting request for anonymous connection to private "
|
|
|
|
"address %s on a TransPort or NATDPort. Possible loop "
|
|
|
|
"in your NAT rules?%s", safe_str_client(socks->address),
|
|
|
|
m);
|
|
|
|
tor_free(m);
|
|
|
|
}
|
2011-01-26 02:39:44 +01:00
|
|
|
} else {
|
2012-06-05 06:49:18 +02:00
|
|
|
#define WARN_INTRVL_PRIV 300
|
|
|
|
static ratelim_t priv_warn_limit = RATELIM_INIT(WARN_INTRVL_PRIV);
|
2012-03-28 09:06:25 +02:00
|
|
|
char *m;
|
|
|
|
if ((m = rate_limit_log(&priv_warn_limit, approx_time()))) {
|
|
|
|
log_warn(LD_NET,
|
|
|
|
"Rejecting SOCKS request for anonymous connection to "
|
|
|
|
"private address %s.%s",
|
|
|
|
safe_str_client(socks->address),m);
|
|
|
|
tor_free(m);
|
|
|
|
}
|
2011-01-26 02:39:44 +01:00
|
|
|
}
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
} /* end "if we should check for internal addresses" */
|
2005-08-15 05:25:40 +02:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Okay. We're still doing a CONNECT, and it wasn't a private
|
2016-10-27 18:03:52 +02:00
|
|
|
* address. Here we do special handling for literal IP addresses,
|
|
|
|
* to see if we should reject this preemptively, and to set up
|
|
|
|
* fields in conn->entry_cfg to tell the exit what AF we want. */
|
2012-10-31 16:26:00 +01:00
|
|
|
{
|
|
|
|
tor_addr_t addr;
|
|
|
|
/* XXX Duplicate call to tor_addr_parse. */
|
|
|
|
if (tor_addr_parse(&addr, socks->address) >= 0) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we reach this point, it's an IPv4 or an IPv6 address. */
|
2012-10-31 16:26:00 +01:00
|
|
|
sa_family_t family = tor_addr_family(&addr);
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2015-01-03 22:11:23 +01:00
|
|
|
if ((family == AF_INET && ! conn->entry_cfg.ipv4_traffic) ||
|
2015-01-19 17:51:08 +01:00
|
|
|
(family == AF_INET6 && ! conn->entry_cfg.ipv6_traffic)) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* You can't do an IPv4 address on a v6-only socks listener,
|
|
|
|
* or vice versa. */
|
2012-10-31 16:26:00 +01:00
|
|
|
log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
|
|
|
|
"family that this listener does not support.");
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
} else if (family == AF_INET6 && socks->socks_version == 4) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* You can't make a socks4 request to an IPv6 address. Socks4
|
|
|
|
* doesn't support that. */
|
2012-10-31 16:26:00 +01:00
|
|
|
log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
2015-01-19 17:56:03 +01:00
|
|
|
} else if (socks->socks_version == 4 &&
|
|
|
|
!conn->entry_cfg.ipv4_traffic) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* You can't do any kind of Socks4 request when IPv4 is forbidden.
|
|
|
|
*
|
|
|
|
* XXX raise this check outside the enclosing block? */
|
2012-10-31 16:26:00 +01:00
|
|
|
log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with "
|
|
|
|
"no IPv4 traffic supported.");
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
2012-11-01 03:40:55 +01:00
|
|
|
} else if (family == AF_INET6) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Tell the exit: we won't accept any ipv4 connection to an IPv6
|
|
|
|
* address. */
|
2015-01-03 22:11:23 +01:00
|
|
|
conn->entry_cfg.ipv4_traffic = 0;
|
2012-11-01 03:40:55 +01:00
|
|
|
} else if (family == AF_INET) {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Tell the exit: we won't accept any ipv6 connection to an IPv4
|
|
|
|
* address. */
|
2015-01-03 22:11:23 +01:00
|
|
|
conn->entry_cfg.ipv6_traffic = 0;
|
2012-10-31 16:26:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* we never allow IPv6 answers on socks4. (TODO: Is this smart?) */
|
2012-11-01 03:03:54 +01:00
|
|
|
if (socks->socks_version == 4)
|
2015-01-03 22:11:23 +01:00
|
|
|
conn->entry_cfg.ipv6_traffic = 0;
|
2012-11-01 03:03:54 +01:00
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Still handling CONNECT. Now, check for exit enclaves. (Which we
|
2017-02-09 17:48:11 +01:00
|
|
|
* don't do on BEGIN_DIR, or when there is a chosen exit.)
|
2016-10-27 18:03:52 +02:00
|
|
|
*
|
|
|
|
* TODO: Should we remove this? Exit enclaves are nutty and don't
|
|
|
|
* work very well
|
2015-01-18 21:10:35 +01:00
|
|
|
*/
|
2007-10-28 09:16:19 +01:00
|
|
|
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
|
2005-08-15 05:25:40 +02:00
|
|
|
/* see if we can find a suitable enclave exit */
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
const node_t *r =
|
2005-08-15 05:25:40 +02:00
|
|
|
router_find_exact_exit_enclave(socks->address, socks->port);
|
|
|
|
if (r) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP,
|
|
|
|
"Redirecting address %s to exit at enclave router %s",
|
2011-05-30 21:41:46 +02:00
|
|
|
safe_str_client(socks->address), node_describe(r));
|
2005-08-15 05:25:40 +02:00
|
|
|
/* use the hex digest, not nickname, in case there are two
|
|
|
|
routers with this nickname */
|
|
|
|
conn->chosen_exit_name =
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
tor_strdup(hex_str(r->identity, DIGEST_LEN));
|
2008-12-17 15:59:28 +01:00
|
|
|
conn->chosen_exit_optional = 1;
|
2005-08-15 05:25:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Still handling CONNECT: warn or reject if it's using a dangerous
|
|
|
|
* port. */
|
2008-01-20 06:54:15 +01:00
|
|
|
if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
|
|
|
|
if (consider_plaintext_ports(conn, socks->port) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Remember the port so that we will predict that more requests
|
|
|
|
there will happen in the future. */
|
2007-10-28 09:16:19 +01:00
|
|
|
if (!conn->use_begindir) {
|
|
|
|
/* help predict this next time */
|
2008-04-16 02:10:39 +02:00
|
|
|
rep_hist_note_used_port(now, socks->port);
|
2007-10-28 09:16:19 +01:00
|
|
|
}
|
2006-09-22 02:44:07 +02:00
|
|
|
} else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
|
2008-02-19 22:30:24 +01:00
|
|
|
rep_hist_note_used_resolve(now); /* help predict this next time */
|
2008-01-19 21:00:53 +01:00
|
|
|
/* no extra processing needed */
|
2006-09-22 02:44:07 +02:00
|
|
|
} else {
|
2016-11-14 15:16:57 +01:00
|
|
|
/* We should only be doing CONNECT, RESOLVE, or RESOLVE_PTR! */
|
2006-09-22 02:44:07 +02:00
|
|
|
tor_fragile_assert();
|
2005-03-12 05:22:01 +01:00
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
|
|
|
/* Okay. At this point we've set chosen_exit_name if needed, rewritten the
|
|
|
|
* address, and decided not to reject it for any number of reasons. Now
|
|
|
|
* mark the connection as waiting for a circuit, and try to attach it!
|
|
|
|
*/
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2015-01-18 21:10:35 +01:00
|
|
|
|
|
|
|
/* If we were given a circuit to attach to, try to attach. Otherwise,
|
|
|
|
* try to find a good one and attach to that. */
|
|
|
|
int rv;
|
2015-11-13 19:38:01 +01:00
|
|
|
if (circ) {
|
|
|
|
rv = connection_ap_handshake_attach_chosen_circuit(conn, circ, cpath);
|
|
|
|
} else {
|
2016-10-27 18:03:52 +02:00
|
|
|
/* We'll try to attach it at the next event loop, or whenever
|
|
|
|
* we call connection_ap_attach_pending() */
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(conn);
|
|
|
|
rv = 0;
|
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
|
|
|
/* If the above function returned 0 then we're waiting for a circuit.
|
|
|
|
* if it returned 1, we're attached. Both are okay. But if it returned
|
|
|
|
* -1, there was an error, so make sure the connection is marked, and
|
|
|
|
* return -1. */
|
|
|
|
if (rv < 0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
if (!base_conn->marked_for_close)
|
2008-03-17 04:37:54 +01:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
|
2006-02-03 12:37:19 +01:00
|
|
|
return -1;
|
2004-11-15 08:50:15 +01:00
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2005-08-15 05:25:40 +02:00
|
|
|
return 0;
|
2004-04-01 04:41:41 +02:00
|
|
|
} else {
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we get here, it's a request for a .onion address! */
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2016-03-31 15:29:46 +02:00
|
|
|
/* If .onion address requests are disabled, refuse the request */
|
|
|
|
if (!conn->entry_cfg.onion_traffic) {
|
|
|
|
log_warn(LD_APP, "Onion address %s requested from a port with .onion "
|
|
|
|
"disabled", safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Check whether it's RESOLVE or RESOLVE_PTR. We don't handle those
|
|
|
|
* for hidden service addresses. */
|
2007-02-12 04:01:36 +01:00
|
|
|
if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) {
|
2004-08-07 02:19:14 +02:00
|
|
|
/* if it's a resolve request, fail it right now, rather than
|
|
|
|
* building all the circuits and then realizing it won't work. */
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"Resolve requests to hidden services not allowed. Failing.");
|
2005-12-14 21:40:40 +01:00
|
|
|
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,
|
2007-07-10 19:14:51 +02:00
|
|
|
0,NULL,-1,TIME_MAX);
|
2005-12-14 21:40:40 +01:00
|
|
|
connection_mark_unattached_ap(conn,
|
2007-02-07 07:54:27 +01:00
|
|
|
END_STREAM_REASON_SOCKSPROTOCOL |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
|
2004-11-15 08:50:15 +01:00
|
|
|
return -1;
|
2004-08-07 02:19:14 +02:00
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* If we were passed a circuit, then we need to fail. .onion addresses
|
|
|
|
* only work when we launch our own circuits for now. */
|
2006-03-12 06:04:16 +01:00
|
|
|
if (circ) {
|
|
|
|
log_warn(LD_CONTROL, "Attachstream to a circuit is not "
|
|
|
|
"supported for .onion addresses currently. Failing.");
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-27 21:08:31 +02:00
|
|
|
/* Look up if we have client authorization configured for this hidden
|
|
|
|
* service. If we do, associate it with the rend_data. */
|
|
|
|
rend_service_authorization_t *client_auth =
|
|
|
|
rend_client_lookup_service_authorization(socks->address);
|
|
|
|
|
2016-05-09 19:43:14 +02:00
|
|
|
const uint8_t *cookie = NULL;
|
2015-04-27 21:08:31 +02:00
|
|
|
rend_auth_type_t auth_type = REND_NO_AUTH;
|
|
|
|
if (client_auth) {
|
|
|
|
log_info(LD_REND, "Using previously configured client authorization "
|
|
|
|
"for hidden service request.");
|
|
|
|
auth_type = client_auth->auth_type;
|
|
|
|
cookie = client_auth->descriptor_cookie;
|
|
|
|
}
|
|
|
|
|
2015-01-18 21:10:35 +01:00
|
|
|
/* Fill in the rend_data field so we can start doing a connection to
|
|
|
|
* a hidden service. */
|
|
|
|
rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
|
2016-06-09 13:50:25 +02:00
|
|
|
rend_data_client_create(socks->address, NULL, (char *) cookie,
|
|
|
|
auth_type);
|
2015-04-27 21:08:31 +02:00
|
|
|
if (rend_data == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-05-31 20:51:30 +02:00
|
|
|
const char *onion_address = rend_data_get_address(rend_data);
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_REND,"Got a hidden service request for ID '%s'",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Lookup the given onion address. If invalid, stop right now.
|
|
|
|
* Otherwise, we might have it in the cache or not. */
|
2015-01-26 23:42:42 +01:00
|
|
|
unsigned int refetch_desc = 0;
|
2015-01-18 21:10:35 +01:00
|
|
|
rend_cache_entry_t *entry = NULL;
|
|
|
|
const int rend_cache_lookup_result =
|
2016-05-31 20:51:30 +02:00
|
|
|
rend_cache_lookup_entry(onion_address, -1, &entry);
|
2015-01-18 21:10:35 +01:00
|
|
|
if (rend_cache_lookup_result < 0) {
|
2015-01-26 23:42:42 +01:00
|
|
|
switch (-rend_cache_lookup_result) {
|
|
|
|
case EINVAL:
|
|
|
|
/* We should already have rejected this address! */
|
|
|
|
log_warn(LD_BUG,"Invalid service name '%s'",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2015-01-26 23:42:42 +01:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
case ENOENT:
|
2016-10-27 18:03:52 +02:00
|
|
|
/* We didn't have this; we should look it up. */
|
2015-01-26 23:42:42 +01:00
|
|
|
refetch_desc = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
log_warn(LD_BUG, "Unknown cache lookup error %d",
|
|
|
|
rend_cache_lookup_result);
|
|
|
|
return -1;
|
|
|
|
}
|
2004-04-18 11:04:37 +02:00
|
|
|
}
|
2008-02-19 22:30:24 +01:00
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* Help predict that we'll want to do hidden service circuits in the
|
|
|
|
* future. We're not sure if it will need a stable circuit yet, but
|
|
|
|
* we know we'll need *something*. */
|
2008-02-19 22:30:24 +01:00
|
|
|
rep_hist_note_used_internal(now, 0, 1);
|
|
|
|
|
2015-01-26 23:42:42 +01:00
|
|
|
/* Now we have a descriptor but is it usable or not? If not, refetch.
|
|
|
|
* Also, a fetch could have been requested if the onion address was not
|
|
|
|
* found in the cache previously. */
|
|
|
|
if (refetch_desc || !rend_client_any_intro_points_usable(entry)) {
|
2015-11-27 18:54:57 +01:00
|
|
|
connection_ap_mark_as_non_pending_circuit(conn);
|
2015-01-26 23:42:42 +01:00
|
|
|
base_conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
|
|
|
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
|
2016-05-31 20:51:30 +02:00
|
|
|
safe_str_client(onion_address));
|
2015-01-26 23:42:42 +01:00
|
|
|
rend_client_refetch_v2_renddesc(rend_data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-27 18:03:52 +02:00
|
|
|
/* We have the descriptor! So launch a connection to the HS. */
|
2015-01-26 23:42:42 +01:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
|
|
|
log_info(LD_REND, "Descriptor is here. Great.");
|
2016-10-27 18:03:52 +02:00
|
|
|
|
|
|
|
/* We'll try to attach it at the next event loop, or whenever
|
|
|
|
* we call connection_ap_attach_pending() */
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(conn);
|
2005-12-07 00:43:52 +01:00
|
|
|
return 0;
|
2004-04-01 04:41:41 +02:00
|
|
|
}
|
2015-01-18 21:10:35 +01:00
|
|
|
|
2004-11-29 09:34:54 +01:00
|
|
|
return 0; /* unreached but keeps the compiler happy */
|
2004-02-18 02:21:20 +01:00
|
|
|
}
|
|
|
|
|
2006-08-10 11:01:54 +02:00
|
|
|
#ifdef TRANS_PF
|
|
|
|
static int pf_socket = -1;
|
2008-08-06 18:32:17 +02:00
|
|
|
int
|
2006-08-10 11:01:54 +02:00
|
|
|
get_pf_socket(void)
|
|
|
|
{
|
|
|
|
int pf;
|
2009-05-27 23:55:51 +02:00
|
|
|
/* This should be opened before dropping privileges. */
|
2006-08-10 11:01:54 +02:00
|
|
|
if (pf_socket >= 0)
|
|
|
|
return pf_socket;
|
|
|
|
|
2016-09-01 19:50:38 +02:00
|
|
|
#if defined(OpenBSD)
|
2006-08-10 11:01:54 +02:00
|
|
|
/* only works on OpenBSD */
|
2010-11-20 06:58:33 +01:00
|
|
|
pf = tor_open_cloexec("/dev/pf", O_RDONLY, 0);
|
2006-08-10 11:01:54 +02:00
|
|
|
#else
|
|
|
|
/* works on NetBSD and FreeBSD */
|
2010-11-20 06:58:33 +01:00
|
|
|
pf = tor_open_cloexec("/dev/pf", O_RDWR, 0);
|
2006-08-10 11:01:54 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (pf < 0) {
|
|
|
|
log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pf_socket = pf;
|
2006-12-04 06:09:09 +01:00
|
|
|
return pf_socket;
|
2006-08-10 11:01:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-02-04 16:09:54 +01:00
|
|
|
#if defined(TRANS_NETFILTER) || defined(TRANS_PF) || defined(TRANS_TPROXY)
|
2014-04-03 22:41:54 +02:00
|
|
|
/** Try fill in the address of <b>req</b> from the socket configured
|
|
|
|
* with <b>conn</b>. */
|
|
|
|
static int
|
2014-02-10 11:23:51 +01:00
|
|
|
destination_from_socket(entry_connection_t *conn, socks_request_t *req)
|
2006-08-10 11:01:37 +02:00
|
|
|
{
|
2008-08-07 21:13:39 +02:00
|
|
|
struct sockaddr_storage orig_dst;
|
2006-08-10 11:01:37 +02:00
|
|
|
socklen_t orig_dst_len = sizeof(orig_dst);
|
2008-08-07 21:13:39 +02:00
|
|
|
tor_addr_t addr;
|
2006-08-10 11:01:37 +02:00
|
|
|
|
2017-05-15 17:16:50 +02:00
|
|
|
#ifdef TRANS_TPROXY
|
|
|
|
if (get_options()->TransProxyType_parsed == TPT_TPROXY) {
|
2015-02-04 16:09:54 +01:00
|
|
|
if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
|
|
|
|
&orig_dst_len) < 0) {
|
|
|
|
int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
|
|
|
|
log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-02-10 11:23:51 +01:00
|
|
|
#ifdef TRANS_NETFILTER
|
2015-03-04 12:12:41 +01:00
|
|
|
int rv = -1;
|
2014-12-23 16:51:33 +01:00
|
|
|
switch (ENTRY_TO_CONN(conn)->socket_family) {
|
|
|
|
#ifdef TRANS_NETFILTER_IPV4
|
|
|
|
case AF_INET:
|
|
|
|
rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST,
|
|
|
|
(struct sockaddr*)&orig_dst, &orig_dst_len);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef TRANS_NETFILTER_IPV6
|
|
|
|
case AF_INET6:
|
|
|
|
rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IPV6, IP6T_SO_ORIGINAL_DST,
|
|
|
|
(struct sockaddr*)&orig_dst, &orig_dst_len);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
2014-12-23 16:53:40 +01:00
|
|
|
log_warn(LD_BUG,
|
|
|
|
"Received transparent data from an unsuported socket family %d",
|
|
|
|
ENTRY_TO_CONN(conn)->socket_family);
|
2014-12-23 16:51:33 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (rv < 0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
|
2006-08-10 11:01:37 +02:00
|
|
|
log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-04 16:09:54 +01:00
|
|
|
goto done;
|
2014-02-10 11:23:51 +01:00
|
|
|
#elif defined(TRANS_PF)
|
|
|
|
if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
|
|
|
|
&orig_dst_len) < 0) {
|
|
|
|
int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
|
|
|
|
log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-04 16:09:54 +01:00
|
|
|
goto done;
|
2014-02-10 11:23:51 +01:00
|
|
|
#else
|
|
|
|
(void)conn;
|
|
|
|
(void)req;
|
|
|
|
log_warn(LD_BUG, "Unable to determine destination from socket.");
|
|
|
|
return -1;
|
|
|
|
#endif
|
2006-08-10 11:01:37 +02:00
|
|
|
|
2015-02-04 16:09:54 +01:00
|
|
|
done:
|
2008-08-07 21:13:39 +02:00
|
|
|
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
|
2012-11-01 03:18:55 +01:00
|
|
|
tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
|
2006-08-10 11:01:37 +02:00
|
|
|
|
2006-08-10 11:02:26 +02:00
|
|
|
return 0;
|
2014-02-10 11:23:51 +01:00
|
|
|
}
|
2014-04-03 22:54:31 +02:00
|
|
|
#endif
|
2014-02-10 11:23:51 +01:00
|
|
|
|
2014-04-03 22:54:31 +02:00
|
|
|
#ifdef TRANS_PF
|
2014-02-10 11:23:51 +01:00
|
|
|
static int
|
|
|
|
destination_from_pf(entry_connection_t *conn, socks_request_t *req)
|
|
|
|
{
|
2008-08-07 21:13:39 +02:00
|
|
|
struct sockaddr_storage proxy_addr;
|
2006-08-10 11:01:37 +02:00
|
|
|
socklen_t proxy_addr_len = sizeof(proxy_addr);
|
2008-08-07 21:13:39 +02:00
|
|
|
struct sockaddr *proxy_sa = (struct sockaddr*) &proxy_addr;
|
2006-08-10 11:01:37 +02:00
|
|
|
struct pfioc_natlook pnl;
|
2008-08-07 21:13:39 +02:00
|
|
|
tor_addr_t addr;
|
2006-08-10 11:01:37 +02:00
|
|
|
int pf = -1;
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&proxy_addr,
|
2006-08-10 11:01:37 +02:00
|
|
|
&proxy_addr_len) < 0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
|
2006-09-30 00:33:40 +02:00
|
|
|
log_warn(LD_NET, "getsockname() to determine transocks destination "
|
|
|
|
"failed: %s", tor_socket_strerror(e));
|
2006-08-10 11:01:37 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-03 20:09:07 +01:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (get_options()->TransProxyType_parsed == TPT_IPFW) {
|
|
|
|
/* ipfw(8) is used and in this case getsockname returned the original
|
|
|
|
destination */
|
2014-02-03 20:13:08 +01:00
|
|
|
if (tor_addr_from_sockaddr(&addr, proxy_sa, &req->port) < 0) {
|
2014-02-03 20:09:07 +01:00
|
|
|
tor_fragile_assert();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-08-10 11:01:37 +02:00
|
|
|
memset(&pnl, 0, sizeof(pnl));
|
|
|
|
pnl.proto = IPPROTO_TCP;
|
|
|
|
pnl.direction = PF_OUT;
|
2008-08-07 21:13:39 +02:00
|
|
|
if (proxy_sa->sa_family == AF_INET) {
|
|
|
|
struct sockaddr_in *sin = (struct sockaddr_in *)proxy_sa;
|
|
|
|
pnl.af = AF_INET;
|
2011-07-20 18:55:42 +02:00
|
|
|
pnl.saddr.v4.s_addr = tor_addr_to_ipv4n(&ENTRY_TO_CONN(conn)->addr);
|
|
|
|
pnl.sport = htons(ENTRY_TO_CONN(conn)->port);
|
2008-08-07 21:13:39 +02:00
|
|
|
pnl.daddr.v4.s_addr = sin->sin_addr.s_addr;
|
|
|
|
pnl.dport = sin->sin_port;
|
|
|
|
} else if (proxy_sa->sa_family == AF_INET6) {
|
|
|
|
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)proxy_sa;
|
|
|
|
pnl.af = AF_INET6;
|
2011-07-20 18:55:42 +02:00
|
|
|
memcpy(&pnl.saddr.v6, tor_addr_to_in6(&ENTRY_TO_CONN(conn)->addr),
|
2008-08-07 21:13:39 +02:00
|
|
|
sizeof(struct in6_addr));
|
2011-07-20 18:55:42 +02:00
|
|
|
pnl.sport = htons(ENTRY_TO_CONN(conn)->port);
|
2008-08-08 04:41:34 +02:00
|
|
|
memcpy(&pnl.daddr.v6, &sin6->sin6_addr, sizeof(struct in6_addr));
|
2008-08-07 21:13:39 +02:00
|
|
|
pnl.dport = sin6->sin6_port;
|
|
|
|
} else {
|
|
|
|
log_warn(LD_NET, "getsockname() gave an unexpected address family (%d)",
|
|
|
|
(int)proxy_sa->sa_family);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-08-10 11:02:12 +02:00
|
|
|
|
2006-08-10 11:01:54 +02:00
|
|
|
pf = get_pf_socket();
|
|
|
|
if (pf<0)
|
2006-08-10 11:01:37 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
|
|
|
|
log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-08-08 04:41:34 +02:00
|
|
|
if (pnl.af == AF_INET) {
|
|
|
|
tor_addr_from_ipv4n(&addr, pnl.rdaddr.v4.s_addr);
|
|
|
|
} else if (pnl.af == AF_INET6) {
|
2008-08-08 14:58:17 +02:00
|
|
|
tor_addr_from_in6(&addr, &pnl.rdaddr.v6);
|
2008-08-07 21:13:39 +02:00
|
|
|
} else {
|
|
|
|
tor_fragile_assert();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-11-01 03:18:55 +01:00
|
|
|
tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
|
2006-08-10 11:01:37 +02:00
|
|
|
req->port = ntohs(pnl.rdport);
|
|
|
|
|
|
|
|
return 0;
|
2014-02-10 11:23:51 +01:00
|
|
|
}
|
2014-04-03 22:54:31 +02:00
|
|
|
#endif
|
2014-02-10 11:23:51 +01:00
|
|
|
|
|
|
|
/** Fetch the original destination address and port from a
|
|
|
|
* system-specific interface and put them into a
|
|
|
|
* socks_request_t as if they came from a socks request.
|
|
|
|
*
|
|
|
|
* Return -1 if an error prevents fetching the destination,
|
|
|
|
* else return 0.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
connection_ap_get_original_destination(entry_connection_t *conn,
|
|
|
|
socks_request_t *req)
|
|
|
|
{
|
|
|
|
#ifdef TRANS_NETFILTER
|
|
|
|
return destination_from_socket(conn, req);
|
|
|
|
#elif defined(TRANS_PF)
|
|
|
|
const or_options_t *options = get_options();
|
|
|
|
|
|
|
|
if (options->TransProxyType_parsed == TPT_PF_DIVERT)
|
|
|
|
return destination_from_socket(conn, req);
|
|
|
|
|
2015-03-04 12:24:51 +01:00
|
|
|
if (options->TransProxyType_parsed == TPT_DEFAULT ||
|
|
|
|
options->TransProxyType_parsed == TPT_IPFW)
|
2014-02-10 11:23:51 +01:00
|
|
|
return destination_from_pf(conn, req);
|
|
|
|
|
|
|
|
(void)conn;
|
|
|
|
(void)req;
|
|
|
|
log_warn(LD_BUG, "Proxy destination determination mechanism %s unknown.",
|
|
|
|
options->TransProxyType);
|
|
|
|
return -1;
|
2006-08-10 11:02:26 +02:00
|
|
|
#else
|
|
|
|
(void)conn;
|
|
|
|
(void)req;
|
|
|
|
log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no "
|
|
|
|
"transparent proxy method was configured.");
|
|
|
|
return -1;
|
|
|
|
#endif
|
2006-08-10 11:01:37 +02:00
|
|
|
}
|
|
|
|
|
2006-02-03 12:37:19 +01:00
|
|
|
/** connection_edge_process_inbuf() found a conn in state
|
|
|
|
* socks_wait. See if conn->inbuf has the right bytes to proceed with
|
|
|
|
* the socks handshake.
|
|
|
|
*
|
|
|
|
* If the handshake is complete, send it to
|
|
|
|
* connection_ap_handshake_rewrite_and_attach().
|
|
|
|
*
|
2006-12-02 23:47:46 +01:00
|
|
|
* Return -1 if an unexpected error with conn occurs (and mark it for close),
|
2006-11-17 04:34:58 +01:00
|
|
|
* else return 0.
|
2006-02-03 12:37:19 +01:00
|
|
|
*/
|
|
|
|
static int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_handshake_process_socks(entry_connection_t *conn)
|
2006-02-03 12:37:19 +01:00
|
|
|
{
|
|
|
|
socks_request_t *socks;
|
|
|
|
int sockshere;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2011-06-29 23:44:29 +02:00
|
|
|
int had_reply = 0;
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_t *base_conn = ENTRY_TO_CONN(conn);
|
2006-02-03 12:37:19 +01:00
|
|
|
|
|
|
|
tor_assert(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(base_conn->type == CONN_TYPE_AP);
|
|
|
|
tor_assert(base_conn->state == AP_CONN_STATE_SOCKS_WAIT);
|
2006-02-03 12:37:19 +01:00
|
|
|
tor_assert(conn->socks_request);
|
|
|
|
socks = conn->socks_request;
|
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_APP,"entered.");
|
2006-02-03 12:37:19 +01:00
|
|
|
|
2016-08-02 19:15:10 +02:00
|
|
|
sockshere = fetch_from_buf_socks(base_conn->inbuf, socks,
|
|
|
|
options->TestSocks, options->SafeSocks);
|
2011-06-29 23:44:29 +02:00
|
|
|
|
|
|
|
if (socks->replylen) {
|
|
|
|
had_reply = 1;
|
2011-07-13 18:13:12 +02:00
|
|
|
connection_write_to_buf((const char*)socks->reply, socks->replylen,
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn);
|
2011-06-29 23:44:29 +02:00
|
|
|
socks->replylen = 0;
|
2011-09-25 16:32:43 +02:00
|
|
|
if (sockshere == -1) {
|
|
|
|
/* An invalid request just got a reply, no additional
|
|
|
|
* one is necessary. */
|
|
|
|
socks->has_finished = 1;
|
|
|
|
}
|
2011-06-29 23:44:29 +02:00
|
|
|
}
|
|
|
|
|
2006-02-03 12:37:19 +01:00
|
|
|
if (sockshere == 0) {
|
2011-06-29 23:44:29 +02:00
|
|
|
log_debug(LD_APP,"socks handshake not all here yet.");
|
2006-02-03 12:37:19 +01:00
|
|
|
return 0;
|
|
|
|
} else if (sockshere == -1) {
|
2011-06-29 23:44:29 +02:00
|
|
|
if (!had_reply) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,"Fetching socks handshake failed. Closing.");
|
2006-10-20 19:54:43 +02:00
|
|
|
connection_ap_handshake_socks_reply(conn, NULL, 0,
|
|
|
|
END_STREAM_REASON_SOCKSPROTOCOL);
|
2006-02-03 12:37:19 +01:00
|
|
|
}
|
|
|
|
connection_mark_unattached_ap(conn,
|
2007-02-07 07:54:27 +01:00
|
|
|
END_STREAM_REASON_SOCKSPROTOCOL |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
|
2006-02-03 12:37:19 +01:00
|
|
|
return -1;
|
|
|
|
} /* else socks handshake is done, continue processing */
|
|
|
|
|
2006-12-13 01:28:56 +01:00
|
|
|
if (SOCKS_COMMAND_IS_CONNECT(socks->command))
|
2006-10-20 19:54:36 +02:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
|
2006-02-03 12:37:19 +01:00
|
|
|
else
|
2006-10-20 19:54:36 +02:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0);
|
2006-02-03 12:37:19 +01:00
|
|
|
|
2010-08-06 21:29:15 +02:00
|
|
|
return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
|
2006-02-03 12:37:19 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:06:02 +01:00
|
|
|
/** connection_init_accepted_conn() found a new trans AP conn.
|
|
|
|
* Get the original destination and send it to
|
|
|
|
* connection_ap_handshake_rewrite_and_attach().
|
2006-08-10 11:01:37 +02:00
|
|
|
*
|
|
|
|
* Return -1 if an unexpected error with conn (and it should be marked
|
|
|
|
* for close), else return 0.
|
|
|
|
*/
|
2006-11-14 01:06:02 +01:00
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_process_transparent(entry_connection_t *conn)
|
2006-08-10 11:01:37 +02:00
|
|
|
{
|
|
|
|
socks_request_t *socks;
|
|
|
|
|
|
|
|
tor_assert(conn);
|
|
|
|
tor_assert(conn->socks_request);
|
|
|
|
socks = conn->socks_request;
|
|
|
|
|
|
|
|
/* pretend that a socks handshake completed so we don't try to
|
|
|
|
* send a socks reply down a transparent conn */
|
|
|
|
socks->command = SOCKS_COMMAND_CONNECT;
|
|
|
|
socks->has_finished = 1;
|
|
|
|
|
|
|
|
log_debug(LD_APP,"entered.");
|
|
|
|
|
|
|
|
if (connection_ap_get_original_destination(conn, socks) < 0) {
|
|
|
|
log_warn(LD_APP,"Fetching original destination failed. Closing.");
|
2006-11-14 01:06:45 +01:00
|
|
|
connection_mark_unattached_ap(conn,
|
|
|
|
END_STREAM_REASON_CANT_FETCH_ORIG_DEST);
|
2006-08-10 11:01:37 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* we have the original destination */
|
|
|
|
|
2006-10-20 19:54:36 +02:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
|
2006-08-10 11:01:37 +02:00
|
|
|
|
2010-08-06 21:29:15 +02:00
|
|
|
return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
|
2006-08-10 11:01:37 +02:00
|
|
|
}
|
|
|
|
|
2006-12-29 03:47:51 +01:00
|
|
|
/** connection_edge_process_inbuf() found a conn in state natd_wait. See if
|
|
|
|
* conn-\>inbuf has the right bytes to proceed. See FreeBSD's libalias(3) and
|
|
|
|
* ProxyEncodeTcpStream() in src/lib/libalias/alias_proxy.c for the encoding
|
|
|
|
* form of the original destination.
|
2006-11-14 01:06:31 +01:00
|
|
|
*
|
|
|
|
* If the original destination is complete, send it to
|
|
|
|
* connection_ap_handshake_rewrite_and_attach().
|
|
|
|
*
|
|
|
|
* Return -1 if an unexpected error with conn (and it should be marked
|
|
|
|
* for close), else return 0.
|
|
|
|
*/
|
|
|
|
static int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_process_natd(entry_connection_t *conn)
|
2006-11-14 01:06:31 +01:00
|
|
|
{
|
|
|
|
char tmp_buf[36], *tbuf, *daddr;
|
|
|
|
size_t tlen = 30;
|
2006-11-14 01:06:45 +01:00
|
|
|
int err, port_ok;
|
2006-11-14 01:06:31 +01:00
|
|
|
socks_request_t *socks;
|
|
|
|
|
|
|
|
tor_assert(conn);
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(ENTRY_TO_CONN(conn)->state == AP_CONN_STATE_NATD_WAIT);
|
2006-11-14 01:06:31 +01:00
|
|
|
tor_assert(conn->socks_request);
|
|
|
|
socks = conn->socks_request;
|
|
|
|
|
|
|
|
log_debug(LD_APP,"entered.");
|
|
|
|
|
|
|
|
/* look for LF-terminated "[DEST ip_addr port]"
|
|
|
|
* where ip_addr is a dotted-quad and port is in string form */
|
2011-07-20 18:55:42 +02:00
|
|
|
err = connection_fetch_from_buf_line(ENTRY_TO_CONN(conn), tmp_buf, &tlen);
|
2006-11-14 01:06:31 +01:00
|
|
|
if (err == 0)
|
|
|
|
return 0;
|
|
|
|
if (err < 0) {
|
2010-10-30 06:08:47 +02:00
|
|
|
log_warn(LD_APP,"NATD handshake failed (DEST too long). Closing");
|
2006-11-14 01:06:31 +01:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:06:45 +01:00
|
|
|
if (strcmpstart(tmp_buf, "[DEST ")) {
|
2010-10-30 06:08:47 +02:00
|
|
|
log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
|
2006-12-13 01:28:56 +01:00
|
|
|
"said: %s",
|
2006-11-14 01:06:45 +01:00
|
|
|
escaped(tmp_buf));
|
2006-11-14 01:06:31 +01:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:06:45 +01:00
|
|
|
daddr = tbuf = &tmp_buf[0] + 6; /* after end of "[DEST " */
|
2007-07-08 05:45:47 +02:00
|
|
|
if (!(tbuf = strchr(tbuf, ' '))) {
|
2010-10-30 06:08:47 +02:00
|
|
|
log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
|
2007-07-08 05:45:47 +02:00
|
|
|
"said: %s",
|
|
|
|
escaped(tmp_buf));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*tbuf++ = '\0';
|
2006-11-14 01:06:31 +01:00
|
|
|
|
|
|
|
/* pretend that a socks handshake completed so we don't try to
|
|
|
|
* send a socks reply down a natd conn */
|
2006-11-14 01:06:45 +01:00
|
|
|
strlcpy(socks->address, daddr, sizeof(socks->address));
|
2006-11-14 19:05:01 +01:00
|
|
|
socks->port = (uint16_t)
|
|
|
|
tor_parse_long(tbuf, 10, 1, 65535, &port_ok, &daddr);
|
2006-11-14 01:06:45 +01:00
|
|
|
if (!port_ok) {
|
2010-10-30 06:08:47 +02:00
|
|
|
log_warn(LD_APP,"NATD handshake failed; port %s is ill-formed or out "
|
2006-11-14 01:06:45 +01:00
|
|
|
"of range.", escaped(tbuf));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:06:31 +01:00
|
|
|
socks->command = SOCKS_COMMAND_CONNECT;
|
|
|
|
socks->has_finished = 1;
|
|
|
|
|
|
|
|
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2006-11-14 01:06:31 +01:00
|
|
|
|
2010-08-06 21:29:15 +02:00
|
|
|
return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
|
2006-11-14 01:06:31 +01:00
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Iterate over the two bytes of stream_id until we get one that is not
|
|
|
|
* already in use; return it. Return 0 if can't get a unique stream_id.
|
2003-12-19 22:25:44 +01:00
|
|
|
*/
|
2012-12-12 20:53:18 +01:00
|
|
|
streamid_t
|
2006-07-23 09:37:35 +02:00
|
|
|
get_unique_stream_id_by_circ(origin_circuit_t *circ)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
edge_connection_t *tmpconn;
|
2008-07-23 17:58:30 +02:00
|
|
|
streamid_t test_stream_id;
|
2003-12-19 22:25:44 +01:00
|
|
|
uint32_t attempts=0;
|
|
|
|
|
2010-08-16 00:29:27 +02:00
|
|
|
again:
|
2003-12-19 22:25:44 +01:00
|
|
|
test_stream_id = circ->next_stream_id++;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (++attempts > 1<<16) {
|
2003-12-19 22:25:44 +01:00
|
|
|
/* Make sure we don't loop forever if all stream_id's are used. */
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_APP,"No unused stream IDs. Failing.");
|
2003-12-19 22:25:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (test_stream_id == 0)
|
|
|
|
goto again;
|
2004-11-28 10:05:49 +01:00
|
|
|
for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream)
|
|
|
|
if (tmpconn->stream_id == test_stream_id)
|
2003-12-19 22:25:44 +01:00
|
|
|
goto again;
|
|
|
|
return test_stream_id;
|
|
|
|
}
|
|
|
|
|
2011-07-18 19:56:22 +02:00
|
|
|
/** Return true iff <b>conn</b> is linked to a circuit and configured to use
|
|
|
|
* an exit that supports optimistic data. */
|
|
|
|
static int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_supports_optimistic_data(const entry_connection_t *conn)
|
2011-07-18 19:56:22 +02:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
|
2011-07-18 19:56:22 +02:00
|
|
|
/* We can only send optimistic data if we're connected to an open
|
|
|
|
general circuit. */
|
2011-07-20 18:55:42 +02:00
|
|
|
if (edge_conn->on_circuit == NULL ||
|
|
|
|
edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN ||
|
2014-09-22 02:02:12 +02:00
|
|
|
(edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
|
|
|
|
edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_REND_JOINED))
|
2011-07-18 19:56:22 +02:00
|
|
|
return 0;
|
|
|
|
|
2011-07-20 17:02:39 +02:00
|
|
|
return conn->may_use_optimistic_data;
|
2011-07-18 19:56:22 +02:00
|
|
|
}
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/** Return a bitmask of BEGIN_FLAG_* flags that we should transmit in the
|
|
|
|
* RELAY_BEGIN cell for <b>ap_conn</b>. */
|
2012-11-01 03:41:20 +01:00
|
|
|
static uint32_t
|
|
|
|
connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
|
|
|
|
{
|
|
|
|
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn);
|
|
|
|
const node_t *exitnode = NULL;
|
|
|
|
const crypt_path_t *cpath_layer = edge_conn->cpath_layer;
|
|
|
|
uint32_t flags = 0;
|
2012-11-14 21:20:28 +01:00
|
|
|
|
|
|
|
/* No flags for begindir */
|
2012-11-01 03:41:20 +01:00
|
|
|
if (ap_conn->use_begindir)
|
|
|
|
return 0;
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/* No flags for hidden services. */
|
2012-11-01 03:41:20 +01:00
|
|
|
if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
|
|
|
return 0;
|
|
|
|
|
2012-11-14 21:20:28 +01:00
|
|
|
/* If only IPv4 is supported, no flags */
|
2015-01-03 22:11:23 +01:00
|
|
|
if (ap_conn->entry_cfg.ipv4_traffic && !ap_conn->entry_cfg.ipv6_traffic)
|
2012-11-01 03:41:20 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (! cpath_layer ||
|
|
|
|
! cpath_layer->extend_info)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-03 22:11:23 +01:00
|
|
|
if (!ap_conn->entry_cfg.ipv4_traffic)
|
2012-11-01 03:41:20 +01:00
|
|
|
flags |= BEGIN_FLAG_IPV4_NOT_OK;
|
|
|
|
|
|
|
|
exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest);
|
|
|
|
|
2015-01-03 22:11:23 +01:00
|
|
|
if (ap_conn->entry_cfg.ipv6_traffic && exitnode) {
|
2012-11-01 03:41:20 +01:00
|
|
|
tor_addr_t a;
|
|
|
|
tor_addr_make_null(&a, AF_INET6);
|
|
|
|
if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port,
|
|
|
|
exitnode)
|
|
|
|
!= ADDR_POLICY_REJECTED) {
|
2012-11-14 21:20:28 +01:00
|
|
|
/* Only say "IPv6 OK" if the exit node supports IPv6. Otherwise there's
|
|
|
|
* no point. */
|
2012-11-01 03:41:20 +01:00
|
|
|
flags |= BEGIN_FLAG_IPV6_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 16:09:06 +01:00
|
|
|
if (flags == BEGIN_FLAG_IPV6_OK) {
|
|
|
|
/* When IPv4 and IPv6 are both allowed, consider whether to say we
|
|
|
|
* prefer IPv6. Otherwise there's no point in declaring a preference */
|
2015-01-03 22:11:23 +01:00
|
|
|
if (ap_conn->entry_cfg.prefer_ipv6)
|
2012-11-14 16:09:06 +01:00
|
|
|
flags |= BEGIN_FLAG_IPV6_PREFERRED;
|
|
|
|
}
|
|
|
|
|
2012-11-01 03:41:20 +01:00
|
|
|
if (flags == BEGIN_FLAG_IPV4_NOT_OK) {
|
2013-05-17 20:50:45 +02:00
|
|
|
log_warn(LD_EDGE, "I'm about to ask a node for a connection that I "
|
2012-11-01 03:41:20 +01:00
|
|
|
"am telling it to fulfil with neither IPv4 nor IPv6. That's "
|
2013-05-17 20:50:45 +02:00
|
|
|
"not going to work. Did you perhaps ask for an IPv6 address "
|
|
|
|
"on an IPv4Only port, or vice versa?");
|
2012-11-01 03:41:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Write a relay begin cell, using destaddr and destport from ap_conn's
|
|
|
|
* socks_request field, and send it down circ.
|
|
|
|
*
|
|
|
|
* If ap_conn is broken, mark it for close and return -1. Else return 0.
|
|
|
|
*/
|
2017-05-02 15:33:49 +02:00
|
|
|
MOCK_IMPL(int,
|
|
|
|
connection_ap_handshake_send_begin,(entry_connection_t *ap_conn))
|
2003-11-11 03:41:31 +01:00
|
|
|
{
|
2003-10-04 10:19:23 +02:00
|
|
|
char payload[CELL_PAYLOAD_SIZE];
|
|
|
|
int payload_len;
|
2006-12-13 01:28:56 +01:00
|
|
|
int begin_type;
|
2016-07-14 06:04:02 +02:00
|
|
|
const or_options_t *options = get_options();
|
2007-03-24 16:58:11 +01:00
|
|
|
origin_circuit_t *circ;
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn);
|
|
|
|
connection_t *base_conn = TO_CONN(edge_conn);
|
|
|
|
tor_assert(edge_conn->on_circuit);
|
|
|
|
circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit);
|
2003-09-18 10:11:31 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(base_conn->type == CONN_TYPE_AP);
|
|
|
|
tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(ap_conn->socks_request);
|
2006-12-13 01:28:56 +01:00
|
|
|
tor_assert(SOCKS_COMMAND_IS_CONNECT(ap_conn->socks_request->command));
|
2003-11-11 03:41:31 +01:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_conn->stream_id = get_unique_stream_id_by_circ(circ);
|
|
|
|
if (edge_conn->stream_id==0) {
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX+ Instead of closing this stream, we should make it get
|
2011-03-25 22:57:15 +01:00
|
|
|
* retried on another circuit. */
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
2011-03-25 22:57:15 +01:00
|
|
|
|
|
|
|
/* Mark this circuit "unusable for new streams". */
|
2013-02-20 00:29:17 +01:00
|
|
|
mark_circuit_unusable_for_new_conns(circ);
|
2004-04-05 09:41:31 +02:00
|
|
|
return -1;
|
2003-12-19 22:25:44 +01:00
|
|
|
}
|
2003-10-04 10:19:23 +02:00
|
|
|
|
2012-11-01 03:41:20 +01:00
|
|
|
/* Set up begin cell flags. */
|
|
|
|
edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn);
|
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
|
2012-10-12 18:22:13 +02:00
|
|
|
(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
|
2005-02-22 01:53:08 +01:00
|
|
|
ap_conn->socks_request->address : "",
|
|
|
|
ap_conn->socks_request->port);
|
2008-02-22 20:09:45 +01:00
|
|
|
payload_len = (int)strlen(payload)+1;
|
2012-11-01 03:04:09 +01:00
|
|
|
if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) {
|
2012-10-25 05:39:28 +02:00
|
|
|
set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags));
|
|
|
|
payload_len += 4;
|
|
|
|
}
|
2003-10-04 10:19:23 +02:00
|
|
|
|
2009-08-11 21:16:16 +02:00
|
|
|
log_info(LD_APP,
|
2015-08-17 20:34:50 +02:00
|
|
|
"Sending relay cell %d on circ %u to begin stream %d.",
|
2009-08-11 21:16:16 +02:00
|
|
|
(int)ap_conn->use_begindir,
|
2015-08-17 20:34:50 +02:00
|
|
|
(unsigned)circ->base_.n_circ_id,
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_conn->stream_id);
|
2003-10-04 10:19:23 +02:00
|
|
|
|
2007-10-28 09:16:19 +01:00
|
|
|
begin_type = ap_conn->use_begindir ?
|
|
|
|
RELAY_COMMAND_BEGIN_DIR : RELAY_COMMAND_BEGIN;
|
2016-07-14 06:04:02 +02:00
|
|
|
|
|
|
|
/* Check that circuits are anonymised, based on their type. */
|
2006-12-13 03:49:45 +01:00
|
|
|
if (begin_type == RELAY_COMMAND_BEGIN) {
|
2016-07-14 06:04:02 +02:00
|
|
|
/* This connection is a standard OR connection.
|
|
|
|
* Make sure its path length is anonymous, or that we're in a
|
|
|
|
* non-anonymous mode. */
|
|
|
|
assert_circ_anonymity_ok(circ, options);
|
|
|
|
} else if (begin_type == RELAY_COMMAND_BEGIN_DIR) {
|
|
|
|
/* This connection is a begindir directory connection.
|
|
|
|
* Look at the linked directory connection to access the directory purpose.
|
2017-03-01 23:49:35 +01:00
|
|
|
* If a BEGINDIR connection is ever not linked, that's a bug. */
|
|
|
|
if (BUG(!base_conn->linked)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-07-14 06:04:02 +02:00
|
|
|
connection_t *linked_dir_conn_base = base_conn->linked_conn;
|
2017-03-01 23:49:35 +01:00
|
|
|
/* If the linked connection has been unlinked by other code, we can't send
|
|
|
|
* a begin cell on it. */
|
|
|
|
if (!linked_dir_conn_base) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-07-14 06:04:02 +02:00
|
|
|
/* Sensitive directory connections must have an anonymous path length.
|
|
|
|
* Otherwise, directory connections are typically one-hop.
|
|
|
|
* This matches the earlier check for directory connection path anonymity
|
2017-04-21 21:08:28 +02:00
|
|
|
* in directory_initiate_request(). */
|
2016-10-26 01:30:50 +02:00
|
|
|
if (purpose_needs_anonymity(linked_dir_conn_base->purpose,
|
|
|
|
TO_DIR_CONN(linked_dir_conn_base)->router_purpose,
|
|
|
|
TO_DIR_CONN(linked_dir_conn_base)->requested_resource)) {
|
2016-07-14 06:04:02 +02:00
|
|
|
assert_circ_anonymity_ok(circ, options);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* This code was written for the two connection types BEGIN and BEGIN_DIR
|
|
|
|
*/
|
|
|
|
tor_assert_unreached();
|
2006-12-13 03:49:45 +01:00
|
|
|
}
|
2006-12-13 01:28:56 +01:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_edge_send_command(edge_conn, begin_type,
|
2006-12-13 23:42:52 +01:00
|
|
|
begin_type == RELAY_COMMAND_BEGIN ? payload : NULL,
|
2007-03-24 16:57:51 +01:00
|
|
|
begin_type == RELAY_COMMAND_BEGIN ? payload_len : 0) < 0)
|
2004-04-05 09:41:31 +02:00
|
|
|
return -1; /* circuit is closed, don't continue */
|
2003-10-04 10:19:23 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_conn->package_window = STREAMWINDOW_START;
|
|
|
|
edge_conn->deliver_window = STREAMWINDOW_START;
|
|
|
|
base_conn->state = AP_CONN_STATE_CONNECT_WAIT;
|
2012-11-02 19:22:21 +01:00
|
|
|
log_info(LD_APP,"Address/port sent, ap socket "TOR_SOCKET_T_FORMAT
|
2013-03-10 13:32:58 +01:00
|
|
|
", n_circ_id %u",
|
|
|
|
base_conn->s, (unsigned)circ->base_.n_circ_id);
|
2006-10-20 19:54:36 +02:00
|
|
|
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
|
2011-07-18 18:56:45 +02:00
|
|
|
|
|
|
|
/* If there's queued-up data, send it now */
|
2011-07-20 18:55:42 +02:00
|
|
|
if ((connection_get_inbuf_len(base_conn) ||
|
2011-07-18 21:38:05 +02:00
|
|
|
ap_conn->sending_optimistic_data) &&
|
2011-07-18 19:56:22 +02:00
|
|
|
connection_ap_supports_optimistic_data(ap_conn)) {
|
2011-07-21 15:49:00 +02:00
|
|
|
log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data",
|
2011-09-07 20:13:57 +02:00
|
|
|
(long)connection_get_inbuf_len(base_conn),
|
2011-09-08 02:26:58 +02:00
|
|
|
ap_conn->sending_optimistic_data ?
|
2016-08-02 19:40:19 +02:00
|
|
|
(long)buf_datalen(ap_conn->sending_optimistic_data) : 0);
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_edge_package_raw_inbuf(edge_conn, 1, NULL) < 0) {
|
|
|
|
connection_mark_for_close(base_conn);
|
2011-07-18 19:56:22 +02:00
|
|
|
}
|
2011-07-18 18:56:45 +02:00
|
|
|
}
|
|
|
|
|
2004-04-05 09:41:31 +02:00
|
|
|
return 0;
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
2004-06-17 20:13:09 +02:00
|
|
|
/** Write a relay resolve cell, using destaddr and destport from ap_conn's
|
|
|
|
* socks_request field, and send it down circ.
|
|
|
|
*
|
|
|
|
* If ap_conn is broken, mark it for close and return -1. Else return 0.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
|
2004-06-17 20:13:09 +02:00
|
|
|
{
|
2006-09-22 02:43:55 +02:00
|
|
|
int payload_len, command;
|
2004-06-17 20:13:09 +02:00
|
|
|
const char *string_addr;
|
2008-12-19 19:52:00 +01:00
|
|
|
char inaddr_buf[REVERSE_LOOKUP_NAME_BUF_LEN];
|
2007-03-24 16:58:11 +01:00
|
|
|
origin_circuit_t *circ;
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn);
|
|
|
|
connection_t *base_conn = TO_CONN(edge_conn);
|
|
|
|
tor_assert(edge_conn->on_circuit);
|
|
|
|
circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit);
|
2006-09-22 02:43:55 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_assert(base_conn->type == CONN_TYPE_AP);
|
|
|
|
tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
|
2004-06-17 20:13:09 +02:00
|
|
|
tor_assert(ap_conn->socks_request);
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL);
|
2004-06-17 20:13:09 +02:00
|
|
|
|
2006-12-13 01:28:56 +01:00
|
|
|
command = ap_conn->socks_request->command;
|
|
|
|
tor_assert(SOCKS_COMMAND_IS_RESOLVE(command));
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
edge_conn->stream_id = get_unique_stream_id_by_circ(circ);
|
|
|
|
if (edge_conn->stream_id==0) {
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX+ Instead of closing this stream, we should make it get
|
2011-03-25 22:57:15 +01:00
|
|
|
* retried on another circuit. */
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
2011-03-25 22:57:15 +01:00
|
|
|
|
|
|
|
/* Mark this circuit "unusable for new streams". */
|
2013-02-20 00:29:17 +01:00
|
|
|
mark_circuit_unusable_for_new_conns(circ);
|
2004-06-17 20:13:09 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-09-22 02:43:55 +02:00
|
|
|
if (command == SOCKS_COMMAND_RESOLVE) {
|
|
|
|
string_addr = ap_conn->socks_request->address;
|
2008-02-22 20:09:45 +01:00
|
|
|
payload_len = (int)strlen(string_addr)+1;
|
2006-09-22 02:43:55 +02:00
|
|
|
} else {
|
2008-12-19 19:52:00 +01:00
|
|
|
/* command == SOCKS_COMMAND_RESOLVE_PTR */
|
|
|
|
const char *a = ap_conn->socks_request->address;
|
|
|
|
tor_addr_t addr;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* We're doing a reverse lookup. The input could be an IP address, or
|
|
|
|
* could be an .in-addr.arpa or .ip6.arpa address */
|
2012-11-15 04:20:01 +01:00
|
|
|
r = tor_addr_parse_PTR_name(&addr, a, AF_UNSPEC, 1);
|
2008-12-19 19:52:00 +01:00
|
|
|
if (r <= 0) {
|
|
|
|
log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(a));
|
2006-09-22 02:43:55 +02:00
|
|
|
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-12-19 19:52:00 +01:00
|
|
|
|
2011-10-11 17:47:13 +02:00
|
|
|
r = tor_addr_to_PTR_name(inaddr_buf, sizeof(inaddr_buf), &addr);
|
2008-12-19 19:52:00 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warn(LD_BUG, "Couldn't generate reverse lookup hostname of %s",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(a));
|
2008-12-19 19:52:00 +01:00
|
|
|
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
|
|
|
return -1;
|
2007-05-25 20:49:26 +02:00
|
|
|
}
|
2008-12-19 19:52:00 +01:00
|
|
|
|
2006-09-22 02:43:55 +02:00
|
|
|
string_addr = inaddr_buf;
|
2008-02-22 20:09:45 +01:00
|
|
|
payload_len = (int)strlen(inaddr_buf)+1;
|
2009-01-14 07:36:33 +01:00
|
|
|
tor_assert(payload_len <= (int)sizeof(inaddr_buf));
|
|
|
|
}
|
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_APP,
|
2011-07-20 18:55:42 +02:00
|
|
|
"Sending relay cell to begin stream %d.", edge_conn->stream_id);
|
2004-06-17 20:13:09 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_edge_send_command(edge_conn,
|
2006-07-23 09:37:35 +02:00
|
|
|
RELAY_COMMAND_RESOLVE,
|
2007-03-24 16:57:51 +01:00
|
|
|
string_addr, payload_len) < 0)
|
2004-06-17 20:13:09 +02:00
|
|
|
return -1; /* circuit is closed, don't continue */
|
|
|
|
|
2013-03-18 20:13:59 +01:00
|
|
|
if (!base_conn->address) {
|
|
|
|
/* This might be unnecessary. XXXX */
|
2016-03-28 22:36:51 +02:00
|
|
|
base_conn->address = tor_addr_to_str_dup(&base_conn->addr);
|
2013-03-18 20:13:59 +01:00
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
|
2012-11-02 19:22:21 +01:00
|
|
|
log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT
|
2013-03-10 13:32:58 +01:00
|
|
|
", n_circ_id %u",
|
|
|
|
base_conn->s, (unsigned)circ->base_.n_circ_id);
|
2006-10-20 19:54:36 +02:00
|
|
|
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0);
|
2004-06-17 20:13:09 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-05 00:50:13 +02:00
|
|
|
/** Make an AP connection_t linked to the connection_t <b>partner</b>. make a
|
|
|
|
* new linked connection pair, and attach one side to the conn, connection_add
|
|
|
|
* it, initialize it to circuit_wait, and call
|
|
|
|
* connection_ap_handshake_attach_circuit(conn) on it.
|
2004-05-10 06:42:22 +02:00
|
|
|
*
|
2012-06-05 00:50:13 +02:00
|
|
|
* Return the newly created end of the linked connection pair, or -1 if error.
|
2004-04-01 00:02:13 +02:00
|
|
|
*/
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *
|
2009-08-11 21:16:16 +02:00
|
|
|
connection_ap_make_link(connection_t *partner,
|
|
|
|
char *address, uint16_t port,
|
2011-07-08 21:54:30 +02:00
|
|
|
const char *digest,
|
|
|
|
int session_group, int isolation_flags,
|
|
|
|
int use_begindir, int want_onehop)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_connection_t *conn;
|
|
|
|
connection_t *base_conn;
|
2006-06-06 02:06:52 +02:00
|
|
|
|
2008-06-14 00:52:17 +02:00
|
|
|
log_info(LD_APP,"Making internal %s tunnel to %s:%d ...",
|
2009-09-28 15:08:32 +02:00
|
|
|
want_onehop ? "direct" : "anonymized",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(address), port);
|
2004-04-01 00:02:13 +02:00
|
|
|
|
2011-11-24 19:01:56 +01:00
|
|
|
conn = entry_connection_new(CONN_TYPE_AP, tor_addr_family(&partner->addr));
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn = ENTRY_TO_CONN(conn);
|
|
|
|
base_conn->linked = 1; /* so that we can add it safely below. */
|
2004-04-01 00:02:13 +02:00
|
|
|
|
|
|
|
/* populate conn->socks_request */
|
|
|
|
|
|
|
|
/* leave version at zero, so the socks_reply is empty */
|
|
|
|
conn->socks_request->socks_version = 0;
|
|
|
|
conn->socks_request->has_finished = 0; /* waiting for 'connected' */
|
2004-10-27 08:48:16 +02:00
|
|
|
strlcpy(conn->socks_request->address, address,
|
|
|
|
sizeof(conn->socks_request->address));
|
2004-04-01 00:02:13 +02:00
|
|
|
conn->socks_request->port = port;
|
2007-10-28 09:16:19 +01:00
|
|
|
conn->socks_request->command = SOCKS_COMMAND_CONNECT;
|
|
|
|
conn->want_onehop = want_onehop;
|
|
|
|
conn->use_begindir = use_begindir;
|
|
|
|
if (use_begindir) {
|
2006-12-13 01:28:56 +01:00
|
|
|
conn->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+2);
|
|
|
|
conn->chosen_exit_name[0] = '$';
|
2007-12-03 23:04:19 +01:00
|
|
|
tor_assert(digest);
|
2006-12-13 01:28:56 +01:00
|
|
|
base16_encode(conn->chosen_exit_name+1,HEX_DIGEST_LEN+1,
|
|
|
|
digest, DIGEST_LEN);
|
|
|
|
}
|
2004-04-01 00:02:13 +02:00
|
|
|
|
2011-07-08 21:54:30 +02:00
|
|
|
/* Populate isolation fields. */
|
2011-08-02 16:48:39 +02:00
|
|
|
conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
|
2011-07-08 21:54:30 +02:00
|
|
|
conn->original_dest_address = tor_strdup(address);
|
2015-01-03 22:11:23 +01:00
|
|
|
conn->entry_cfg.session_group = session_group;
|
|
|
|
conn->entry_cfg.isolation_flags = isolation_flags;
|
2011-07-08 21:54:30 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->address = tor_strdup("(Tor_internal)");
|
|
|
|
tor_addr_make_unspec(&base_conn->addr);
|
|
|
|
base_conn->port = 0;
|
2004-04-01 00:02:13 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_link_connections(partner, base_conn);
|
2009-08-11 21:16:16 +02:00
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (connection_add(base_conn) < 0) { /* no space, forget it */
|
|
|
|
connection_free(base_conn);
|
2007-04-21 19:26:12 +02:00
|
|
|
return NULL;
|
2004-04-01 00:02:13 +02:00
|
|
|
}
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2004-04-01 00:02:13 +02:00
|
|
|
|
2007-07-05 16:50:05 +02:00
|
|
|
control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
|
|
|
|
|
2004-04-01 01:06:16 +02:00
|
|
|
/* attaching to a dirty circuit is fine */
|
2015-11-13 19:38:01 +01:00
|
|
|
connection_ap_mark_as_pending_circuit(conn);
|
2007-06-09 07:17:33 +02:00
|
|
|
log_info(LD_APP,"... application connection created and linked.");
|
2007-04-21 19:26:12 +02:00
|
|
|
return conn;
|
2004-04-01 00:02:13 +02:00
|
|
|
}
|
|
|
|
|
2008-02-08 22:13:15 +01:00
|
|
|
/** Notify any interested controller connections about a new hostname resolve
|
|
|
|
* or resolve error. Takes the same arguments as does
|
|
|
|
* connection_ap_handshake_socks_resolved(). */
|
2007-07-10 19:14:51 +02:00
|
|
|
static void
|
2011-07-20 18:55:42 +02:00
|
|
|
tell_controller_about_resolved_result(entry_connection_t *conn,
|
2007-07-10 19:14:51 +02:00
|
|
|
int answer_type,
|
|
|
|
size_t answer_len,
|
|
|
|
const char *answer,
|
|
|
|
int ttl,
|
|
|
|
time_t expires)
|
|
|
|
{
|
2013-04-03 18:50:27 +02:00
|
|
|
expires = time(NULL) + ttl;
|
|
|
|
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
|
2012-05-01 22:39:49 +02:00
|
|
|
char *cp = tor_dup_ip(ntohl(get_uint32(answer)));
|
2007-07-10 19:14:51 +02:00
|
|
|
control_event_address_mapped(conn->socks_request->address,
|
2013-04-03 18:50:51 +02:00
|
|
|
cp, expires, NULL, 0);
|
2010-10-02 03:31:09 +02:00
|
|
|
tor_free(cp);
|
|
|
|
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
|
2007-07-10 19:14:51 +02:00
|
|
|
char *cp = tor_strndup(answer, answer_len);
|
|
|
|
control_event_address_mapped(conn->socks_request->address,
|
2013-04-03 18:50:51 +02:00
|
|
|
cp, expires, NULL, 0);
|
2007-07-10 19:14:51 +02:00
|
|
|
tor_free(cp);
|
|
|
|
} else {
|
|
|
|
control_event_address_mapped(conn->socks_request->address,
|
2013-04-03 18:50:51 +02:00
|
|
|
"<error>", time(NULL)+ttl,
|
|
|
|
"error=yes", 0);
|
2007-07-10 19:14:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-22 14:38:36 +01:00
|
|
|
/**
|
|
|
|
* As connection_ap_handshake_socks_resolved, but take a tor_addr_t to send
|
|
|
|
* as the answer.
|
|
|
|
*/
|
2014-03-28 03:24:48 +01:00
|
|
|
void
|
2013-12-22 14:38:36 +01:00
|
|
|
connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn,
|
|
|
|
const tor_addr_t *answer,
|
|
|
|
int ttl,
|
|
|
|
time_t expires)
|
|
|
|
{
|
|
|
|
if (tor_addr_family(answer) == AF_INET) {
|
|
|
|
uint32_t a = tor_addr_to_ipv4n(answer); /* network order */
|
|
|
|
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
|
|
|
|
(uint8_t*)&a,
|
|
|
|
ttl, expires);
|
|
|
|
} else if (tor_addr_family(answer) == AF_INET6) {
|
|
|
|
const uint8_t *a = tor_addr_to_in6_addr8(answer);
|
|
|
|
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV6,16,
|
|
|
|
a,
|
|
|
|
ttl, expires);
|
|
|
|
} else {
|
|
|
|
log_warn(LD_BUG, "Got called with address of unexpected family %d",
|
|
|
|
tor_addr_family(answer));
|
|
|
|
connection_ap_handshake_socks_resolved(conn,
|
|
|
|
RESOLVED_TYPE_ERROR,0,NULL,-1,-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-16 00:39:04 +01:00
|
|
|
/** Send an answer to an AP connection that has requested a DNS lookup via
|
|
|
|
* SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or -1
|
|
|
|
* for unreachable; the answer should be in the format specified in the socks
|
|
|
|
* extensions document. <b>ttl</b> is the ttl for the answer, or -1 on
|
|
|
|
* certain errors or for values that didn't come via DNS. <b>expires</b> is
|
|
|
|
* a time when the answer expires, or -1 or TIME_MAX if there's a good TTL.
|
2005-03-17 13:38:37 +01:00
|
|
|
**/
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX the use of the ttl and expires fields is nutty. Let's make this
|
2008-02-16 00:39:04 +01:00
|
|
|
* interface and those that use it less ugly. */
|
2014-04-02 19:38:50 +02:00
|
|
|
MOCK_IMPL(void,
|
|
|
|
connection_ap_handshake_socks_resolved,(entry_connection_t *conn,
|
2005-06-11 20:52:12 +02:00
|
|
|
int answer_type,
|
|
|
|
size_t answer_len,
|
2010-12-14 01:34:01 +01:00
|
|
|
const uint8_t *answer,
|
2007-07-10 19:14:51 +02:00
|
|
|
int ttl,
|
2014-04-02 19:38:50 +02:00
|
|
|
time_t expires))
|
2004-06-17 20:13:09 +02:00
|
|
|
{
|
2006-09-22 02:43:55 +02:00
|
|
|
char buf[384];
|
2004-10-14 04:47:09 +02:00
|
|
|
size_t replylen;
|
2004-06-17 20:13:09 +02:00
|
|
|
|
2006-12-26 23:41:43 +01:00
|
|
|
if (ttl >= 0) {
|
|
|
|
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
|
2012-10-31 23:27:48 +01:00
|
|
|
tor_addr_t a;
|
|
|
|
tor_addr_from_ipv4n(&a, get_uint32(answer));
|
|
|
|
if (! tor_addr_is_null(&a)) {
|
2012-11-25 19:45:36 +01:00
|
|
|
client_dns_set_addressmap(conn,
|
2012-10-31 23:27:48 +01:00
|
|
|
conn->socks_request->address, &a,
|
|
|
|
conn->chosen_exit_name, ttl);
|
|
|
|
}
|
|
|
|
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
|
|
|
|
tor_addr_t a;
|
|
|
|
tor_addr_from_ipv6_bytes(&a, (char*)answer);
|
|
|
|
if (! tor_addr_is_null(&a)) {
|
2012-11-25 19:45:36 +01:00
|
|
|
client_dns_set_addressmap(conn,
|
2012-10-31 23:27:48 +01:00
|
|
|
conn->socks_request->address, &a,
|
2006-12-26 23:41:43 +01:00
|
|
|
conn->chosen_exit_name, ttl);
|
2012-10-28 22:13:37 +01:00
|
|
|
}
|
2006-12-26 23:41:43 +01:00
|
|
|
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
|
2010-12-14 01:34:01 +01:00
|
|
|
char *cp = tor_strndup((char*)answer, answer_len);
|
2012-11-25 19:45:36 +01:00
|
|
|
client_dns_set_reverse_addressmap(conn,
|
2012-10-28 22:13:37 +01:00
|
|
|
conn->socks_request->address,
|
2006-12-26 23:41:43 +01:00
|
|
|
cp,
|
|
|
|
conn->chosen_exit_name, ttl);
|
|
|
|
tor_free(cp);
|
|
|
|
}
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request) {
|
2007-07-10 19:14:51 +02:00
|
|
|
if (conn->dns_server_request) {
|
|
|
|
/* We had a request on our DNS port: answer it. */
|
2010-12-14 01:34:01 +01:00
|
|
|
dnsserv_resolved(conn, answer_type, answer_len, (char*)answer, ttl);
|
2007-07-10 19:14:51 +02:00
|
|
|
conn->socks_request->has_finished = 1;
|
|
|
|
return;
|
|
|
|
} else {
|
2013-04-03 18:50:27 +02:00
|
|
|
/* This must be a request from the controller. Since answers to those
|
|
|
|
* requests are not cached, they do not generate an ADDRMAP event on
|
|
|
|
* their own. */
|
2007-07-10 19:14:51 +02:00
|
|
|
tell_controller_about_resolved_result(conn, answer_type, answer_len,
|
2010-12-14 01:34:01 +01:00
|
|
|
(char*)answer, ttl, expires);
|
2007-07-10 19:14:51 +02:00
|
|
|
conn->socks_request->has_finished = 1;
|
|
|
|
return;
|
|
|
|
}
|
2008-12-18 16:00:27 +01:00
|
|
|
/* We shouldn't need to free conn here; it gets marked by the caller. */
|
2007-05-25 20:22:42 +02:00
|
|
|
}
|
|
|
|
|
2004-06-17 20:13:09 +02:00
|
|
|
if (conn->socks_request->socks_version == 4) {
|
|
|
|
buf[0] = 0x00; /* version */
|
|
|
|
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
|
2008-08-25 09:06:55 +02:00
|
|
|
buf[1] = SOCKS4_GRANTED;
|
2004-06-17 20:13:09 +02:00
|
|
|
set_uint16(buf+2, 0);
|
|
|
|
memcpy(buf+4, answer, 4); /* address */
|
|
|
|
replylen = SOCKS4_NETWORK_LEN;
|
2008-08-25 09:06:55 +02:00
|
|
|
} else { /* "error" */
|
|
|
|
buf[1] = SOCKS4_REJECT;
|
2004-06-17 20:13:09 +02:00
|
|
|
memset(buf+2, 0, 6);
|
|
|
|
replylen = SOCKS4_NETWORK_LEN;
|
|
|
|
}
|
2007-01-27 19:56:13 +01:00
|
|
|
} else if (conn->socks_request->socks_version == 5) {
|
2004-06-17 20:13:09 +02:00
|
|
|
/* SOCKS5 */
|
|
|
|
buf[0] = 0x05; /* version */
|
|
|
|
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
|
2005-03-01 23:16:15 +01:00
|
|
|
buf[1] = SOCKS5_SUCCEEDED;
|
2004-06-17 20:13:09 +02:00
|
|
|
buf[2] = 0; /* reserved */
|
|
|
|
buf[3] = 0x01; /* IPv4 address type */
|
|
|
|
memcpy(buf+4, answer, 4); /* address */
|
|
|
|
set_uint16(buf+8, 0); /* port == 0. */
|
|
|
|
replylen = 10;
|
|
|
|
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
|
2005-03-01 23:16:15 +01:00
|
|
|
buf[1] = SOCKS5_SUCCEEDED;
|
2004-06-17 20:13:09 +02:00
|
|
|
buf[2] = 0; /* reserved */
|
|
|
|
buf[3] = 0x04; /* IPv6 address type */
|
|
|
|
memcpy(buf+4, answer, 16); /* address */
|
|
|
|
set_uint16(buf+20, 0); /* port == 0. */
|
|
|
|
replylen = 22;
|
2006-09-22 02:43:55 +02:00
|
|
|
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
|
|
|
|
buf[1] = SOCKS5_SUCCEEDED;
|
|
|
|
buf[2] = 0; /* reserved */
|
|
|
|
buf[3] = 0x03; /* Domainname address type */
|
2006-09-22 02:44:07 +02:00
|
|
|
buf[4] = (char)answer_len;
|
|
|
|
memcpy(buf+5, answer, answer_len); /* address */
|
|
|
|
set_uint16(buf+5+answer_len, 0); /* port == 0. */
|
|
|
|
replylen = 5+answer_len+2;
|
2004-06-17 20:13:09 +02:00
|
|
|
} else {
|
2005-03-01 23:16:15 +01:00
|
|
|
buf[1] = SOCKS5_HOST_UNREACHABLE;
|
2004-06-17 20:13:09 +02:00
|
|
|
memset(buf+2, 0, 8);
|
|
|
|
replylen = 10;
|
|
|
|
}
|
2007-01-27 19:56:13 +01:00
|
|
|
} else {
|
|
|
|
/* no socks version info; don't send anything back */
|
|
|
|
return;
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
|
|
|
connection_ap_handshake_socks_reply(conn, buf, replylen,
|
2005-03-17 13:38:37 +01:00
|
|
|
(answer_type == RESOLVED_TYPE_IPV4 ||
|
2011-07-07 05:27:20 +02:00
|
|
|
answer_type == RESOLVED_TYPE_IPV6 ||
|
|
|
|
answer_type == RESOLVED_TYPE_HOSTNAME) ?
|
2006-10-20 19:54:43 +02:00
|
|
|
0 : END_STREAM_REASON_RESOLVEFAILED);
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Send a socks reply to stream <b>conn</b>, using the appropriate
|
2005-03-17 13:38:37 +01:00
|
|
|
* socks version, etc, and mark <b>conn</b> as completed with SOCKS
|
|
|
|
* handshaking.
|
2004-11-04 00:13:28 +01:00
|
|
|
*
|
2007-02-02 19:58:11 +01:00
|
|
|
* If <b>reply</b> is defined, then write <b>replylen</b> bytes of it to conn
|
|
|
|
* and return, else reply based on <b>endreason</b> (one of
|
2007-02-06 03:49:07 +01:00
|
|
|
* END_STREAM_REASON_*). If <b>reply</b> is undefined, <b>endreason</b> can't
|
|
|
|
* be 0 or REASON_DONE. Send endreason to the controller, if appropriate.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
|
2006-10-20 19:54:43 +02:00
|
|
|
size_t replylen, int endreason)
|
2006-09-22 02:43:55 +02:00
|
|
|
{
|
2003-10-04 03:37:01 +02:00
|
|
|
char buf[256];
|
2006-10-20 19:54:43 +02:00
|
|
|
socks5_reply_status_t status =
|
2008-06-11 02:17:02 +02:00
|
|
|
stream_end_reason_to_socks5_response(endreason);
|
2006-10-20 19:54:43 +02:00
|
|
|
|
2005-03-26 07:27:51 +01:00
|
|
|
tor_assert(conn->socks_request); /* make sure it's an AP stream */
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2013-03-18 20:13:59 +01:00
|
|
|
if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) {
|
|
|
|
control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ?
|
|
|
|
STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
|
|
|
|
endreason);
|
|
|
|
}
|
2004-11-03 19:33:07 +01:00
|
|
|
|
2012-11-18 01:30:50 +01:00
|
|
|
/* Flag this stream's circuit as having completed a stream successfully
|
|
|
|
* (for path bias) */
|
2012-12-09 01:37:22 +01:00
|
|
|
if (status == SOCKS5_SUCCEEDED ||
|
|
|
|
endreason == END_STREAM_REASON_RESOLVEFAILED ||
|
|
|
|
endreason == END_STREAM_REASON_CONNECTREFUSED ||
|
|
|
|
endreason == END_STREAM_REASON_CONNRESET ||
|
|
|
|
endreason == END_STREAM_REASON_NOROUTE ||
|
|
|
|
endreason == END_STREAM_REASON_RESOURCELIMIT) {
|
2012-12-10 08:47:04 +01:00
|
|
|
if (!conn->edge_.on_circuit ||
|
2012-11-18 01:30:50 +01:00
|
|
|
!CIRCUIT_IS_ORIGIN(conn->edge_.on_circuit)) {
|
2014-06-03 23:37:49 +02:00
|
|
|
if (endreason != END_STREAM_REASON_RESOLVEFAILED) {
|
|
|
|
log_info(LD_BUG,
|
|
|
|
"No origin circuit for successful SOCKS stream "U64_FORMAT
|
|
|
|
". Reason: %d",
|
|
|
|
U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier),
|
|
|
|
endreason);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Else DNS remaps and failed hidden service lookups can send us
|
|
|
|
* here with END_STREAM_REASON_RESOLVEFAILED; ignore it
|
|
|
|
*
|
|
|
|
* Perhaps we could make the test more precise; we can tell hidden
|
|
|
|
* services by conn->edge_.renddata != NULL; anything analogous for
|
|
|
|
* the DNS remap case?
|
|
|
|
*/
|
2012-11-18 01:30:50 +01:00
|
|
|
} else {
|
2013-01-19 04:37:16 +01:00
|
|
|
// XXX: Hrmm. It looks like optimistic data can't go through this
|
|
|
|
// codepath, but someone should probably test it and make sure.
|
|
|
|
// We don't want to mark optimistically opened streams as successful.
|
|
|
|
pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit));
|
2012-11-18 01:30:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-17 13:38:37 +01:00
|
|
|
if (conn->socks_request->has_finished) {
|
2007-03-04 21:11:46 +01:00
|
|
|
log_warn(LD_BUG, "(Harmless.) duplicate calls to "
|
2006-02-13 10:02:35 +01:00
|
|
|
"connection_ap_handshake_socks_reply.");
|
2005-03-17 13:38:37 +01:00
|
|
|
return;
|
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (replylen) { /* we already have a reply in mind */
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_write_to_buf(reply, replylen, ENTRY_TO_CONN(conn));
|
2005-03-17 13:38:37 +01:00
|
|
|
conn->socks_request->has_finished = 1;
|
2004-03-03 07:26:34 +01:00
|
|
|
return;
|
2003-10-04 03:37:01 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (conn->socks_request->socks_version == 4) {
|
2003-10-04 03:37:01 +02:00
|
|
|
memset(buf,0,SOCKS4_NETWORK_LEN);
|
2005-03-17 13:38:37 +01:00
|
|
|
buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT);
|
2003-10-04 03:37:01 +02:00
|
|
|
/* leave version, destport, destip zero */
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, ENTRY_TO_CONN(conn));
|
2005-03-24 02:11:28 +01:00
|
|
|
} else if (conn->socks_request->socks_version == 5) {
|
2014-02-21 11:14:33 +01:00
|
|
|
size_t buf_len;
|
|
|
|
memset(buf,0,sizeof(buf));
|
|
|
|
if (tor_addr_family(&conn->edge_.base_.addr) == AF_INET) {
|
|
|
|
buf[0] = 5; /* version 5 */
|
|
|
|
buf[1] = (char)status;
|
|
|
|
buf[2] = 0;
|
|
|
|
buf[3] = 1; /* ipv4 addr */
|
2014-02-21 18:27:35 +01:00
|
|
|
/* 4 bytes for the header, 2 bytes for the port, 4 for the address. */
|
2014-02-21 11:14:33 +01:00
|
|
|
buf_len = 10;
|
|
|
|
} else { /* AF_INET6. */
|
|
|
|
buf[0] = 5; /* version 5 */
|
|
|
|
buf[1] = (char)status;
|
|
|
|
buf[2] = 0;
|
|
|
|
buf[3] = 4; /* ipv6 addr */
|
2014-02-21 18:27:35 +01:00
|
|
|
/* 4 bytes for the header, 2 bytes for the port, 16 for the address. */
|
2014-02-21 11:14:33 +01:00
|
|
|
buf_len = 22;
|
|
|
|
}
|
|
|
|
connection_write_to_buf(buf,buf_len,ENTRY_TO_CONN(conn));
|
2003-10-04 03:37:01 +02:00
|
|
|
}
|
2004-04-01 00:02:13 +02:00
|
|
|
/* If socks_version isn't 4 or 5, don't send anything.
|
|
|
|
* This can happen in the case of AP bridges. */
|
2005-03-17 13:38:37 +01:00
|
|
|
conn->socks_request->has_finished = 1;
|
2004-03-03 07:26:34 +01:00
|
|
|
return;
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
2017-02-09 17:48:11 +01:00
|
|
|
/** Read a RELAY_BEGIN or RELAY_BEGIN_DIR cell from <b>cell</b>, decode it, and
|
2012-11-14 21:20:28 +01:00
|
|
|
* place the result in <b>bcell</b>. On success return 0; on failure return
|
|
|
|
* <0 and set *<b>end_reason_out</b> to the end reason we should send back to
|
2012-11-15 18:17:30 +01:00
|
|
|
* the client.
|
|
|
|
*
|
|
|
|
* Return -1 in the case where want to send a RELAY_END cell, and < -1 when
|
|
|
|
* we don't.
|
|
|
|
**/
|
2013-06-06 23:58:28 +02:00
|
|
|
STATIC int
|
2012-10-22 17:28:37 +02:00
|
|
|
begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
|
|
|
|
uint8_t *end_reason_out)
|
|
|
|
{
|
|
|
|
relay_header_t rh;
|
|
|
|
const uint8_t *body, *nul;
|
|
|
|
|
|
|
|
memset(bcell, 0, sizeof(*bcell));
|
|
|
|
*end_reason_out = END_STREAM_REASON_MISC;
|
|
|
|
|
|
|
|
relay_header_unpack(&rh, cell->payload);
|
|
|
|
if (rh.length > RELAY_PAYLOAD_SIZE) {
|
2012-11-15 18:17:30 +01:00
|
|
|
return -2; /*XXXX why not TORPROTOCOL? */
|
2012-10-22 17:28:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bcell->stream_id = rh.stream_id;
|
|
|
|
|
|
|
|
if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
|
|
|
|
bcell->is_begindir = 1;
|
|
|
|
return 0;
|
|
|
|
} else if (rh.command != RELAY_COMMAND_BEGIN) {
|
|
|
|
log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command);
|
|
|
|
*end_reason_out = END_STREAM_REASON_INTERNAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
body = cell->payload + RELAY_HEADER_SIZE;
|
|
|
|
nul = memchr(body, 0, rh.length);
|
|
|
|
if (! nul) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
|
"Relay begin cell has no \\0. Closing.");
|
|
|
|
*end_reason_out = END_STREAM_REASON_TORPROTOCOL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tor_addr_port_split(LOG_PROTOCOL_WARN,
|
|
|
|
(char*)(body),
|
|
|
|
&bcell->address,&bcell->port)<0) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
|
"Unable to parse addr:port in relay begin cell. Closing.");
|
|
|
|
*end_reason_out = END_STREAM_REASON_TORPROTOCOL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (bcell->port == 0) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
|
"Missing port in relay begin cell. Closing.");
|
|
|
|
tor_free(bcell->address);
|
|
|
|
*end_reason_out = END_STREAM_REASON_TORPROTOCOL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (body + rh.length >= nul + 4)
|
|
|
|
bcell->flags = ntohl(get_uint32(nul+1));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-05-25 21:41:31 +02:00
|
|
|
/** A relay 'begin' or 'begin_dir' cell has arrived, and either we are
|
|
|
|
* an exit hop for the circuit, or we are the origin and it is a
|
|
|
|
* rendezvous begin.
|
2004-05-10 06:42:22 +02:00
|
|
|
*
|
|
|
|
* Launch a new exit connection and initialize things appropriately.
|
|
|
|
*
|
|
|
|
* If it's a rendezvous stream, call connection_exit_connect() on
|
|
|
|
* it.
|
|
|
|
*
|
|
|
|
* For general streams, call dns_resolve() on it first, and only call
|
|
|
|
* connection_exit_connect() if the dns answer is already known.
|
|
|
|
*
|
|
|
|
* Note that we don't call connection_add() on the new stream! We wait
|
|
|
|
* for connection_exit_connect() to do that.
|
|
|
|
*
|
2006-10-20 17:26:02 +02:00
|
|
|
* Return -(some circuit end reason) if we want to tear down <b>circ</b>.
|
|
|
|
* Else return 0.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
|
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
edge_connection_t *n_stream;
|
2003-12-19 06:09:51 +01:00
|
|
|
relay_header_t rh;
|
2012-10-22 17:28:37 +02:00
|
|
|
char *address = NULL;
|
|
|
|
uint16_t port = 0;
|
2006-12-25 04:42:38 +01:00
|
|
|
or_circuit_t *or_circ = NULL;
|
2017-06-05 15:35:03 +02:00
|
|
|
origin_circuit_t *origin_circ = NULL;
|
|
|
|
crypt_path_t *layer_hint = NULL;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2012-10-22 17:28:37 +02:00
|
|
|
begin_cell_t bcell;
|
2016-07-05 20:19:31 +02:00
|
|
|
int rv;
|
2012-10-22 17:28:37 +02:00
|
|
|
uint8_t end_reason=0;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2004-04-15 02:03:48 +02:00
|
|
|
assert_circuit_ok(circ);
|
2017-06-05 15:35:03 +02:00
|
|
|
if (!CIRCUIT_IS_ORIGIN(circ)) {
|
2006-12-25 04:42:38 +01:00
|
|
|
or_circ = TO_OR_CIRCUIT(circ);
|
2017-06-05 15:35:03 +02:00
|
|
|
} else {
|
|
|
|
tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
|
|
|
|
origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
|
|
|
layer_hint = origin_circ->cpath->prev;
|
|
|
|
}
|
2003-12-19 06:09:51 +01:00
|
|
|
|
2006-10-20 16:57:46 +02:00
|
|
|
relay_header_unpack(&rh, cell->payload);
|
2010-12-14 01:34:01 +01:00
|
|
|
if (rh.length > RELAY_PAYLOAD_SIZE)
|
2014-12-07 14:47:09 +01:00
|
|
|
return -END_CIRC_REASON_TORPROTOCOL;
|
2006-10-20 16:57:46 +02:00
|
|
|
|
|
|
|
/* Note: we have to use relay_send_command_from_edge here, not
|
|
|
|
* connection_edge_end or connection_edge_send_command, since those require
|
|
|
|
* that we have a stream connected to a circuit, and we don't connect to a
|
2006-10-20 21:11:12 +02:00
|
|
|
* circuit until we have a pending/successful resolve. */
|
2003-10-21 10:37:07 +02:00
|
|
|
|
2010-09-27 23:07:22 +02:00
|
|
|
if (!server_mode(options) &&
|
2006-07-30 06:32:58 +02:00
|
|
|
circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
2006-10-20 21:11:12 +02:00
|
|
|
"Relay begin cell at non-server. Closing.");
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_EXITPOLICY, NULL);
|
2006-07-30 06:32:58 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-05 20:19:31 +02:00
|
|
|
rv = begin_cell_parse(cell, &bcell, &end_reason);
|
|
|
|
if (rv < -1) {
|
2014-12-07 14:47:09 +01:00
|
|
|
return -END_CIRC_REASON_TORPROTOCOL;
|
2016-07-05 20:19:31 +02:00
|
|
|
} else if (rv == -1) {
|
2012-10-22 17:28:37 +02:00
|
|
|
tor_free(bcell.address);
|
2017-06-05 15:35:03 +02:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, layer_hint);
|
2012-10-22 17:28:37 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! bcell.is_begindir) {
|
|
|
|
/* Steal reference */
|
|
|
|
address = bcell.address;
|
|
|
|
port = bcell.port;
|
|
|
|
|
2012-08-25 20:55:39 +02:00
|
|
|
if (or_circ && or_circ->p_chan) {
|
2017-04-25 19:44:06 +02:00
|
|
|
if ((or_circ->is_first_hop ||
|
|
|
|
(!connection_or_digest_is_known_relay(
|
2012-10-09 09:51:33 +02:00
|
|
|
or_circ->p_chan->identity_digest) &&
|
2010-09-27 23:07:22 +02:00
|
|
|
should_refuse_unknown_exits(options)))) {
|
2017-04-25 19:44:06 +02:00
|
|
|
/* Don't let clients use us as a single-hop proxy. It attracts
|
|
|
|
* attackers and users who'd be better off with, well, single-hop
|
|
|
|
* proxies. */
|
2012-08-25 20:55:39 +02:00
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
|
|
"Attempt by %s to open a stream %s. Closing.",
|
|
|
|
safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)),
|
|
|
|
or_circ->is_first_hop ? "on first hop of circuit" :
|
|
|
|
"from unknown relay");
|
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
or_circ->is_first_hop ?
|
|
|
|
END_STREAM_REASON_TORPROTOCOL :
|
|
|
|
END_STREAM_REASON_MISC,
|
|
|
|
NULL);
|
|
|
|
tor_free(address);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-10-01 22:50:11 +02:00
|
|
|
}
|
2006-09-29 05:50:11 +02:00
|
|
|
} else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
|
2010-09-27 23:07:22 +02:00
|
|
|
if (!directory_permits_begindir_requests(options) ||
|
2007-12-01 05:58:53 +01:00
|
|
|
circ->purpose != CIRCUIT_PURPOSE_OR) {
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
2017-06-05 15:35:03 +02:00
|
|
|
END_STREAM_REASON_NOTDIRECTORY, layer_hint);
|
2006-10-20 16:57:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-04-11 20:09:15 +02:00
|
|
|
/* Make sure to get the 'real' address of the previous hop: the
|
2016-01-27 14:51:28 +01:00
|
|
|
* caller might want to know whether the remote IP address has changed,
|
|
|
|
* and we might already have corrected base_.addr[ess] for the relay's
|
2009-04-11 20:09:15 +02:00
|
|
|
* canonical IP address. */
|
2012-08-25 20:55:39 +02:00
|
|
|
if (or_circ && or_circ->p_chan)
|
2012-10-17 17:23:26 +02:00
|
|
|
address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan));
|
2006-12-25 04:42:38 +01:00
|
|
|
else
|
|
|
|
address = tor_strdup("127.0.0.1");
|
2008-02-16 00:39:04 +01:00
|
|
|
port = 1; /* XXXX This value is never actually used anywhere, and there
|
|
|
|
* isn't "really" a connection here. But we
|
|
|
|
* need to set it to something nonzero. */
|
2006-09-29 05:50:11 +02:00
|
|
|
} else {
|
|
|
|
log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command);
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
2017-06-05 15:35:03 +02:00
|
|
|
END_STREAM_REASON_INTERNAL, layer_hint);
|
2006-03-16 00:36:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2012-10-25 06:20:41 +02:00
|
|
|
if (! options->IPv6Exit) {
|
|
|
|
/* I don't care if you prefer IPv6; I can't give you any. */
|
|
|
|
bcell.flags &= ~BEGIN_FLAG_IPV6_PREFERRED;
|
|
|
|
/* If you don't want IPv4, I can't help. */
|
|
|
|
if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) {
|
|
|
|
tor_free(address);
|
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
2017-06-05 15:35:03 +02:00
|
|
|
END_STREAM_REASON_EXITPOLICY, layer_hint);
|
2012-12-29 02:52:24 +01:00
|
|
|
return 0;
|
2012-10-25 06:20:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_EXIT,"Creating new exit connection.");
|
2012-11-15 18:17:30 +01:00
|
|
|
/* The 'AF_INET' here is temporary; we might need to change it later in
|
|
|
|
* connection_exit_connect(). */
|
|
|
|
n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
|
2009-08-18 15:53:08 +02:00
|
|
|
|
2009-07-12 16:33:31 +02:00
|
|
|
/* Remember the tunneled request ID in the new edge connection, so that
|
|
|
|
* we can measure download times. */
|
2012-09-04 09:33:16 +02:00
|
|
|
n_stream->dirreq_id = circ->dirreq_id;
|
2009-08-18 15:53:08 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
n_stream->base_.purpose = EXIT_PURPOSE_CONNECT;
|
2012-10-25 05:39:28 +02:00
|
|
|
n_stream->begincell_flags = bcell.flags;
|
2003-12-19 06:09:51 +01:00
|
|
|
n_stream->stream_id = rh.stream_id;
|
2012-10-12 18:22:13 +02:00
|
|
|
n_stream->base_.port = port;
|
2003-10-15 20:50:16 +02:00
|
|
|
/* leave n_stream->s at -1, because it's not yet valid */
|
2003-09-13 00:45:31 +02:00
|
|
|
n_stream->package_window = STREAMWINDOW_START;
|
|
|
|
n_stream->deliver_window = STREAMWINDOW_START;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
|
2017-06-05 15:35:03 +02:00
|
|
|
tor_assert(origin_circ);
|
2007-08-11 16:13:25 +02:00
|
|
|
log_info(LD_REND,"begin is for rendezvous. configuring stream.");
|
2012-10-12 18:22:13 +02:00
|
|
|
n_stream->base_.address = tor_strdup("(rendezvous)");
|
|
|
|
n_stream->base_.state = EXIT_CONN_STATE_CONNECTING;
|
2008-09-24 16:44:29 +02:00
|
|
|
n_stream->rend_data = rend_data_dup(origin_circ->rend_data);
|
2004-10-17 23:10:41 +02:00
|
|
|
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
|
2004-04-15 02:03:48 +02:00
|
|
|
assert_circuit_ok(circ);
|
2015-01-03 18:34:52 +01:00
|
|
|
|
|
|
|
const int r = rend_service_set_connection_addr_port(n_stream, origin_circ);
|
|
|
|
if (r < 0) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
|
2012-10-12 18:22:13 +02:00
|
|
|
n_stream->base_.port);
|
2014-11-25 16:37:55 +01:00
|
|
|
/* Send back reason DONE because we want to make hidden service port
|
|
|
|
* scanning harder thus instead of returning that the exit policy
|
|
|
|
* didn't match, which makes it obvious that the port is closed,
|
|
|
|
* return DONE and kill the circuit. That way, a user (malicious or
|
|
|
|
* not) needs one circuit per bad port unless it matches the policy of
|
|
|
|
* the hidden service. */
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
2014-11-25 16:37:55 +01:00
|
|
|
END_STREAM_REASON_DONE,
|
2017-06-05 15:35:03 +02:00
|
|
|
layer_hint);
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_free(TO_CONN(n_stream));
|
2004-10-12 17:52:09 +02:00
|
|
|
tor_free(address);
|
2014-11-25 16:37:55 +01:00
|
|
|
|
|
|
|
/* Drop the circuit here since it might be someone deliberately
|
|
|
|
* scanning the hidden service ports. Note that this mitigates port
|
|
|
|
* scanning by adding more work on the attacker side to successfully
|
|
|
|
* scan but does not fully solve it. */
|
2015-01-03 18:34:52 +01:00
|
|
|
if (r < -1)
|
|
|
|
return END_CIRC_AT_ORIGIN;
|
|
|
|
else
|
|
|
|
return 0;
|
2004-04-06 22:25:18 +02:00
|
|
|
}
|
2004-04-15 02:03:48 +02:00
|
|
|
assert_circuit_ok(circ);
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_REND,"Finished assigning addr/port");
|
2006-07-23 09:37:35 +02:00
|
|
|
n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
|
2004-05-06 13:08:04 +02:00
|
|
|
|
2010-08-10 00:50:49 +02:00
|
|
|
/* add it into the linked list of p_streams on this circuit */
|
2006-07-23 09:37:35 +02:00
|
|
|
n_stream->next_stream = origin_circ->p_streams;
|
2005-04-06 08:13:49 +02:00
|
|
|
n_stream->on_circuit = circ;
|
2006-07-23 09:37:35 +02:00
|
|
|
origin_circ->p_streams = n_stream;
|
2004-05-06 13:08:04 +02:00
|
|
|
assert_circuit_ok(circ);
|
|
|
|
|
2015-05-20 19:33:59 +02:00
|
|
|
origin_circ->rend_data->nr_streams++;
|
|
|
|
|
2004-04-06 22:25:18 +02:00
|
|
|
connection_exit_connect(n_stream);
|
2012-11-18 02:51:27 +01:00
|
|
|
|
|
|
|
/* For path bias: This circuit was used successfully */
|
2013-01-19 04:37:16 +01:00
|
|
|
pathbias_mark_use_success(origin_circ);
|
2012-11-18 02:51:27 +01:00
|
|
|
|
2004-10-12 17:52:09 +02:00
|
|
|
tor_free(address);
|
2004-04-06 22:25:18 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_strlower(address);
|
2012-10-12 18:22:13 +02:00
|
|
|
n_stream->base_.address = address;
|
|
|
|
n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
|
2004-04-09 23:31:09 +02:00
|
|
|
/* default to failed, change in dns_resolve if it turns out not to fail */
|
2004-04-06 22:25:18 +02:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (we_are_hibernating()) {
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_HIBERNATING, NULL);
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_free(TO_CONN(n_stream));
|
2004-12-07 22:57:37 +01:00
|
|
|
return 0;
|
2004-10-31 21:28:41 +01:00
|
|
|
}
|
2007-05-10 10:53:05 +02:00
|
|
|
|
|
|
|
n_stream->on_circuit = circ;
|
2004-10-31 21:28:41 +01:00
|
|
|
|
2006-09-29 05:50:11 +02:00
|
|
|
if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
|
2012-10-17 17:15:01 +02:00
|
|
|
tor_addr_t tmp_addr;
|
2007-05-10 10:53:05 +02:00
|
|
|
tor_assert(or_circ);
|
2012-10-17 17:15:01 +02:00
|
|
|
if (or_circ->p_chan &&
|
|
|
|
channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) {
|
|
|
|
tor_addr_copy(&n_stream->base_.addr, &tmp_addr);
|
|
|
|
}
|
2007-05-13 11:25:06 +02:00
|
|
|
return connection_exit_connect_dir(n_stream);
|
2006-09-29 05:50:11 +02:00
|
|
|
}
|
|
|
|
|
2007-05-10 10:53:05 +02:00
|
|
|
log_debug(LD_EXIT,"about to start the dns_resolve().");
|
2007-03-24 16:58:11 +01:00
|
|
|
|
2003-09-13 00:45:31 +02:00
|
|
|
/* send it off to the gethostbyname farm */
|
2007-03-24 16:58:11 +01:00
|
|
|
switch (dns_resolve(n_stream)) {
|
2007-05-25 21:41:31 +02:00
|
|
|
case 1: /* resolve worked; now n_stream is attached to circ. */
|
2004-05-06 13:08:04 +02:00
|
|
|
assert_circuit_ok(circ);
|
2006-05-23 05:08:30 +02:00
|
|
|
log_debug(LD_EXIT,"about to call connection_exit_connect().");
|
2003-10-22 09:55:44 +02:00
|
|
|
connection_exit_connect(n_stream);
|
|
|
|
return 0;
|
2003-09-13 00:45:31 +02:00
|
|
|
case -1: /* resolve failed */
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_RESOLVEFAILED, NULL);
|
2007-05-25 21:41:31 +02:00
|
|
|
/* n_stream got freed. don't touch it. */
|
2004-03-02 08:24:11 +01:00
|
|
|
break;
|
|
|
|
case 0: /* resolve added to pending list */
|
2004-05-06 13:08:04 +02:00
|
|
|
assert_circuit_ok(circ);
|
2007-05-25 21:41:31 +02:00
|
|
|
break;
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-06-17 20:13:09 +02:00
|
|
|
/**
|
2008-12-02 18:35:05 +01:00
|
|
|
* Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the
|
|
|
|
* circuit <b>circ</b>;
|
2004-06-17 20:13:09 +02:00
|
|
|
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-07-23 09:37:35 +02:00
|
|
|
connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
edge_connection_t *dummy_conn;
|
2004-06-17 20:13:09 +02:00
|
|
|
relay_header_t rh;
|
|
|
|
|
2006-07-23 09:37:35 +02:00
|
|
|
assert_circuit_ok(TO_CIRCUIT(circ));
|
2004-06-17 20:13:09 +02:00
|
|
|
relay_header_unpack(&rh, cell->payload);
|
2010-12-14 01:34:01 +01:00
|
|
|
if (rh.length > RELAY_PAYLOAD_SIZE)
|
|
|
|
return -1;
|
2004-06-17 20:13:09 +02:00
|
|
|
|
|
|
|
/* This 'dummy_conn' only exists to remember the stream ID
|
|
|
|
* associated with the resolve request; and to make the
|
|
|
|
* implementation of dns.c more uniform. (We really only need to
|
|
|
|
* remember the circuit, the stream ID, and the hostname to be
|
|
|
|
* resolved; but if we didn't store them in a connection like this,
|
|
|
|
* the housekeeping in dns.c would get way more complicated.)
|
|
|
|
*/
|
2008-09-06 00:09:44 +02:00
|
|
|
dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
|
2004-06-17 20:13:09 +02:00
|
|
|
dummy_conn->stream_id = rh.stream_id;
|
2012-10-12 18:22:13 +02:00
|
|
|
dummy_conn->base_.address = tor_strndup(
|
2010-12-14 01:34:01 +01:00
|
|
|
(char*)cell->payload+RELAY_HEADER_SIZE,
|
|
|
|
rh.length);
|
2012-10-12 18:22:13 +02:00
|
|
|
dummy_conn->base_.port = 0;
|
|
|
|
dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
|
|
|
|
dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE;
|
2004-06-17 20:13:09 +02:00
|
|
|
|
2007-03-24 16:58:11 +01:00
|
|
|
dummy_conn->on_circuit = TO_CIRCUIT(circ);
|
|
|
|
|
2004-06-17 20:13:09 +02:00
|
|
|
/* send it off to the gethostbyname farm */
|
2007-03-24 16:58:11 +01:00
|
|
|
switch (dns_resolve(dummy_conn)) {
|
2005-02-05 22:03:24 +01:00
|
|
|
case -1: /* Impossible to resolve; a resolved cell was sent. */
|
2005-02-06 00:55:21 +01:00
|
|
|
/* Connection freed; don't touch it. */
|
|
|
|
return 0;
|
|
|
|
case 1: /* The result was cached; a resolved cell was sent. */
|
2012-10-12 18:22:13 +02:00
|
|
|
if (!dummy_conn->base_.marked_for_close)
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_free(TO_CONN(dummy_conn));
|
2004-06-17 20:13:09 +02:00
|
|
|
return 0;
|
|
|
|
case 0: /* resolve added to pending list */
|
2006-07-23 09:37:35 +02:00
|
|
|
assert_circuit_ok(TO_CIRCUIT(circ));
|
2005-02-05 22:03:24 +01:00
|
|
|
break;
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-14 15:08:51 +02:00
|
|
|
/** Helper: Return true and set *<b>why_rejected</b> to an optional clarifying
|
|
|
|
* message message iff we do not allow connections to <b>addr</b>:<b>port</b>.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
my_exit_policy_rejects(const tor_addr_t *addr,
|
|
|
|
uint16_t port,
|
|
|
|
const char **why_rejected)
|
|
|
|
{
|
|
|
|
if (router_compare_to_my_exit_policy(addr, port)) {
|
|
|
|
*why_rejected = "";
|
|
|
|
return 1;
|
|
|
|
} else if (tor_addr_family(addr) == AF_INET6 && !get_options()->IPv6Exit) {
|
|
|
|
*why_rejected = " (IPv6 address without IPv6Exit configured)";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Connect to conn's specified addr and port. If it worked, conn
|
|
|
|
* has now been added to the connection_array.
|
|
|
|
*
|
|
|
|
* Send back a connected cell. Include the resolved IP of the destination
|
|
|
|
* address, but <em>only</em> if it's a general exit stream. (Rendezvous
|
|
|
|
* streams must not reveal what IP they connected to.)
|
|
|
|
*/
|
2004-11-09 19:22:17 +01:00
|
|
|
void
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_exit_connect(edge_connection_t *edge_conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2008-08-05 22:08:19 +02:00
|
|
|
const tor_addr_t *addr;
|
2004-10-17 03:57:34 +02:00
|
|
|
uint16_t port;
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_t *conn = TO_CONN(edge_conn);
|
2015-01-24 18:31:12 +01:00
|
|
|
int socket_error = 0, result;
|
2016-10-05 18:38:03 +02:00
|
|
|
const char *why_failed_exit_policy = NULL;
|
|
|
|
|
2016-10-14 15:08:51 +02:00
|
|
|
/* Apply exit policy to non-rendezvous connections. */
|
|
|
|
if (! connection_edge_is_rendezvous_stream(edge_conn) &&
|
|
|
|
my_exit_policy_rejects(&edge_conn->base_.addr,
|
|
|
|
edge_conn->base_.port,
|
|
|
|
&why_failed_exit_policy)) {
|
|
|
|
if (BUG(!why_failed_exit_policy))
|
2016-10-05 18:38:03 +02:00
|
|
|
why_failed_exit_policy = "";
|
|
|
|
log_info(LD_EXIT,"%s:%d failed exit policy%s. Closing.",
|
|
|
|
escaped_safe_str_client(conn->address), conn->port,
|
|
|
|
why_failed_exit_policy);
|
2007-03-24 16:57:51 +01:00
|
|
|
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
|
2006-07-26 21:07:26 +02:00
|
|
|
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
|
2004-05-06 13:08:04 +02:00
|
|
|
connection_free(conn);
|
2003-10-22 09:55:44 +02:00
|
|
|
return;
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
2015-01-24 18:31:12 +01:00
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
if (conn->socket_family != AF_UNIX) {
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
#endif /* defined(HAVE_SYS_UN_H) */
|
|
|
|
addr = &conn->addr;
|
|
|
|
port = conn->port;
|
|
|
|
|
|
|
|
if (tor_addr_family(addr) == AF_INET6)
|
|
|
|
conn->socket_family = AF_INET6;
|
|
|
|
|
|
|
|
log_debug(LD_EXIT, "about to try connecting");
|
|
|
|
result = connection_connect(conn, conn->address,
|
|
|
|
addr, port, &socket_error);
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* In the AF_UNIX case, we expect to have already had conn->port = 1,
|
|
|
|
* tor_addr_make_unspec(conn->addr) (cf. the way we mark in the incoming
|
|
|
|
* case in connection_handle_listener_read()), and conn->address should
|
|
|
|
* have the socket path to connect to.
|
|
|
|
*/
|
|
|
|
tor_assert(conn->address && strlen(conn->address) > 0);
|
2004-10-17 03:57:34 +02:00
|
|
|
|
2015-01-24 18:31:12 +01:00
|
|
|
log_debug(LD_EXIT, "about to try connecting");
|
|
|
|
result = connection_connect_unix(conn, conn->address, &socket_error);
|
|
|
|
#endif /* defined(HAVE_SYS_UN_H) */
|
|
|
|
}
|
2012-10-25 05:45:24 +02:00
|
|
|
|
2015-01-24 18:31:12 +01:00
|
|
|
switch (result) {
|
2011-03-25 21:14:42 +01:00
|
|
|
case -1: {
|
|
|
|
int reason = errno_to_stream_end_reason(socket_error);
|
|
|
|
connection_edge_end(edge_conn, reason);
|
2006-07-26 21:07:26 +02:00
|
|
|
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
|
2004-05-05 03:26:57 +02:00
|
|
|
connection_free(conn);
|
2003-10-22 09:55:44 +02:00
|
|
|
return;
|
2011-03-25 21:14:42 +01:00
|
|
|
}
|
2003-09-16 03:58:46 +02:00
|
|
|
case 0:
|
2003-09-13 00:45:31 +02:00
|
|
|
conn->state = EXIT_CONN_STATE_CONNECTING;
|
|
|
|
|
2009-06-04 20:49:16 +02:00
|
|
|
connection_watch_events(conn, READ_EVENT | WRITE_EVENT);
|
2005-02-23 21:35:26 +01:00
|
|
|
/* writable indicates finish;
|
2009-05-27 23:55:51 +02:00
|
|
|
* readable/error indicates broken link in windows-land. */
|
2003-10-22 09:55:44 +02:00
|
|
|
return;
|
2003-09-16 03:58:46 +02:00
|
|
|
/* case 1: fall through */
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
conn->state = EXIT_CONN_STATE_OPEN;
|
2009-08-11 21:16:16 +02:00
|
|
|
if (connection_get_outbuf_len(conn)) {
|
2013-06-10 18:14:49 +02:00
|
|
|
/* in case there are any queued data cells, from e.g. optimistic data */
|
2016-08-02 19:15:10 +02:00
|
|
|
connection_watch_events(conn, READ_EVENT|WRITE_EVENT);
|
2013-06-10 18:14:49 +02:00
|
|
|
} else {
|
2016-08-02 19:15:10 +02:00
|
|
|
connection_watch_events(conn, READ_EVENT);
|
2003-09-13 00:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* also, deliver a 'connected' cell back through the circuit. */
|
2006-07-26 21:07:37 +02:00
|
|
|
if (connection_edge_is_rendezvous_stream(edge_conn)) {
|
2004-04-06 22:25:18 +02:00
|
|
|
/* don't send an address back! */
|
2006-07-26 21:07:37 +02:00
|
|
|
connection_edge_send_command(edge_conn,
|
2005-05-03 12:04:08 +02:00
|
|
|
RELAY_COMMAND_CONNECTED,
|
2007-03-24 16:57:51 +01:00
|
|
|
NULL, 0);
|
2004-04-06 22:25:18 +02:00
|
|
|
} else { /* normal stream */
|
2012-11-14 16:48:58 +01:00
|
|
|
uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
|
|
|
|
int connected_payload_len =
|
|
|
|
connected_cell_format_payload(connected_payload, &conn->addr,
|
|
|
|
edge_conn->address_ttl);
|
|
|
|
if (connected_payload_len < 0) {
|
|
|
|
connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL);
|
|
|
|
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
|
|
|
|
connection_free(conn);
|
2012-12-05 03:32:11 +01:00
|
|
|
return;
|
2008-08-05 22:08:19 +02:00
|
|
|
}
|
2012-11-14 16:48:58 +01:00
|
|
|
|
2006-07-26 21:07:37 +02:00
|
|
|
connection_edge_send_command(edge_conn,
|
2005-05-03 12:04:08 +02:00
|
|
|
RELAY_COMMAND_CONNECTED,
|
2012-11-14 16:48:58 +01:00
|
|
|
(char*)connected_payload,
|
|
|
|
connected_payload_len);
|
2004-04-06 22:25:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-29 05:50:11 +02:00
|
|
|
/** Given an exit conn that should attach to us as a directory server, open a
|
2007-09-27 07:20:26 +02:00
|
|
|
* bridge connection with a linked connection pair, create a new directory
|
2007-05-29 19:31:13 +02:00
|
|
|
* conn, and join them together. Return 0 on success (or if there was an
|
|
|
|
* error we could send back an end cell for). Return -(some circuit end
|
|
|
|
* reason) if the circuit needs to be torn down. Either connects
|
2008-02-21 04:38:46 +01:00
|
|
|
* <b>exitconn</b>, frees it, or marks it, as appropriate.
|
2006-09-29 05:50:11 +02:00
|
|
|
*/
|
|
|
|
static int
|
2007-05-13 11:25:06 +02:00
|
|
|
connection_exit_connect_dir(edge_connection_t *exitconn)
|
2006-09-29 05:50:11 +02:00
|
|
|
{
|
2007-05-13 11:25:06 +02:00
|
|
|
dir_connection_t *dirconn = NULL;
|
|
|
|
or_circuit_t *circ = TO_OR_CIRCUIT(exitconn->on_circuit);
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2007-04-21 19:26:12 +02:00
|
|
|
log_info(LD_EXIT, "Opening local connection for anonymized directory exit");
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
exitconn->base_.state = EXIT_CONN_STATE_OPEN;
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr));
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2012-10-12 18:22:13 +02:00
|
|
|
tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr);
|
|
|
|
dirconn->base_.port = 0;
|
|
|
|
dirconn->base_.address = tor_strdup(exitconn->base_.address);
|
|
|
|
dirconn->base_.type = CONN_TYPE_DIR;
|
|
|
|
dirconn->base_.purpose = DIR_PURPOSE_SERVER;
|
|
|
|
dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2009-07-12 16:33:31 +02:00
|
|
|
/* Note that the new dir conn belongs to the same tunneled request as
|
|
|
|
* the edge conn, so that we can measure download times. */
|
2012-09-04 09:33:16 +02:00
|
|
|
dirconn->dirreq_id = exitconn->dirreq_id;
|
2009-08-18 15:53:08 +02:00
|
|
|
|
2007-05-13 22:24:43 +02:00
|
|
|
connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn));
|
2007-04-21 19:26:12 +02:00
|
|
|
|
2007-05-13 11:25:06 +02:00
|
|
|
if (connection_add(TO_CONN(exitconn))<0) {
|
|
|
|
connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
|
|
|
|
connection_free(TO_CONN(exitconn));
|
|
|
|
connection_free(TO_CONN(dirconn));
|
2006-09-29 05:50:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-05-25 21:41:31 +02:00
|
|
|
/* link exitconn to circ, now that we know we can use it. */
|
2007-05-13 11:25:06 +02:00
|
|
|
exitconn->next_stream = circ->n_streams;
|
|
|
|
circ->n_streams = exitconn;
|
2007-05-10 10:53:05 +02:00
|
|
|
|
2007-05-13 11:25:06 +02:00
|
|
|
if (connection_add(TO_CONN(dirconn))<0) {
|
|
|
|
connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
|
|
|
|
connection_close_immediate(TO_CONN(exitconn));
|
|
|
|
connection_mark_for_close(TO_CONN(exitconn));
|
|
|
|
connection_free(TO_CONN(dirconn));
|
2006-09-29 05:50:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-05-13 11:25:06 +02:00
|
|
|
connection_start_reading(TO_CONN(dirconn));
|
|
|
|
connection_start_reading(TO_CONN(exitconn));
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2007-05-13 11:25:06 +02:00
|
|
|
if (connection_edge_send_command(exitconn,
|
2007-03-24 16:57:51 +01:00
|
|
|
RELAY_COMMAND_CONNECTED, NULL, 0) < 0) {
|
2007-05-13 11:25:06 +02:00
|
|
|
connection_mark_for_close(TO_CONN(exitconn));
|
|
|
|
connection_mark_for_close(TO_CONN(dirconn));
|
2006-09-29 05:50:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:42:22 +02:00
|
|
|
/** Return 1 if <b>conn</b> is a rendezvous stream, or 0 if
|
|
|
|
* it is a general stream.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2017-01-10 14:35:15 +01:00
|
|
|
connection_edge_is_rendezvous_stream(const edge_connection_t *conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(conn);
|
2017-07-06 12:50:16 +02:00
|
|
|
/* It should not be possible to set both of these structs */
|
|
|
|
tor_assert_nonfatal(!(conn->rend_data && conn->hs_ident));
|
2017-05-02 15:20:26 +02:00
|
|
|
|
|
|
|
if (conn->rend_data || conn->hs_ident) {
|
2004-04-06 23:52:01 +02:00
|
|
|
return 1;
|
2017-05-02 15:20:26 +02:00
|
|
|
}
|
2004-04-06 23:52:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-28 16:22:10 +02:00
|
|
|
/** Return 1 if router <b>exit_node</b> is likely to allow stream <b>conn</b>
|
2005-03-19 07:57:16 +01:00
|
|
|
* to exit from it, or 0 if it probably will not allow it.
|
2004-05-10 06:42:22 +02:00
|
|
|
* (We might be uncertain if conn's destination address has not yet been
|
2009-09-21 05:50:48 +02:00
|
|
|
* resolved.)
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2016-07-28 16:22:10 +02:00
|
|
|
connection_ap_can_use_exit(const entry_connection_t *conn,
|
|
|
|
const node_t *exit_node)
|
2003-11-16 06:33:45 +01:00
|
|
|
{
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2009-12-21 09:48:40 +01:00
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(conn);
|
|
|
|
tor_assert(conn->socks_request);
|
2016-07-28 16:22:10 +02:00
|
|
|
tor_assert(exit_node);
|
2003-11-17 02:20:35 +01:00
|
|
|
|
2004-11-29 09:34:54 +01:00
|
|
|
/* If a particular exit node has been requested for the new connection,
|
|
|
|
* make sure the exit node of the existing circuit matches exactly.
|
|
|
|
*/
|
|
|
|
if (conn->chosen_exit_name) {
|
Initial conversion to use node_t throughout our codebase.
A node_t is an abstraction over routerstatus_t, routerinfo_t, and
microdesc_t. It should try to present a consistent interface to all
of them. There should be a node_t for a server whenever there is
* A routerinfo_t for it in the routerlist
* A routerstatus_t in the current_consensus.
(note that a microdesc_t alone isn't enough to make a node_t exist,
since microdescriptors aren't usable on their own.)
There are three ways to get a node_t right now: looking it up by ID,
looking it up by nickname, and iterating over the whole list of
microdescriptors.
All (or nearly all) functions that are supposed to return "a router"
-- especially those used in building connections and circuits --
should return a node_t, not a routerinfo_t or a routerstatus_t.
A node_t should hold all the *mutable* flags about a node. This
patch moves the is_foo flags from routerinfo_t into node_t. The
flags in routerstatus_t remain, but they get set from the consensus
and should not change.
Some other highlights of this patch are:
* Looking up routerinfo and routerstatus by nickname is now
unified and based on the "look up a node by nickname" function.
This tries to look only at the values from current consensus,
and not get confused by the routerinfo_t->is_named flag, which
could get set for other weird reasons. This changes the
behavior of how authorities (when acting as clients) deal with
nodes that have been listed by nickname.
* I tried not to artificially increase the size of the diff here
by moving functions around. As a result, some functions that
now operate on nodes are now in the wrong file -- they should
get moved to nodelist.c once this refactoring settles down.
This moving should happen as part of a patch that moves
functions AND NOTHING ELSE.
* Some old code is now left around inside #if 0/1 blocks, and
should get removed once I've verified that I don't want it
sitting around to see how we used to do things.
There are still some unimplemented functions: these are flagged
with "UNIMPLEMENTED_NODELIST()." I'll work on filling in the
implementation here, piece by piece.
I wish this patch could have been smaller, but there did not seem to
be any piece of it that was independent from the rest. Moving flags
forces many functions that once returned routerinfo_t * to return
node_t *, which forces their friends to change, and so on.
2010-09-29 21:00:41 +02:00
|
|
|
const node_t *chosen_exit =
|
|
|
|
node_get_by_nickname(conn->chosen_exit_name, 1);
|
2011-05-11 22:39:45 +02:00
|
|
|
if (!chosen_exit || tor_memneq(chosen_exit->identity,
|
2016-07-28 16:22:10 +02:00
|
|
|
exit_node->identity, DIGEST_LEN)) {
|
2004-11-29 09:34:54 +01:00
|
|
|
/* doesn't match */
|
2006-09-22 02:24:27 +02:00
|
|
|
// log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.",
|
|
|
|
// conn->chosen_exit_name, exit->nickname);
|
2004-11-29 09:34:54 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-24 17:26:05 +02:00
|
|
|
if (conn->use_begindir) {
|
|
|
|
/* Internal directory fetches do not count as exiting. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
|
2011-07-15 18:58:13 +02:00
|
|
|
tor_addr_t addr, *addrp = NULL;
|
2005-03-19 07:57:16 +01:00
|
|
|
addr_policy_result_t r;
|
2012-11-01 03:04:25 +01:00
|
|
|
if (0 == tor_addr_parse(&addr, conn->socks_request->address)) {
|
|
|
|
addrp = &addr;
|
2015-01-03 22:11:23 +01:00
|
|
|
} else if (!conn->entry_cfg.ipv4_traffic && conn->entry_cfg.ipv6_traffic) {
|
2012-11-01 03:04:25 +01:00
|
|
|
tor_addr_make_null(&addr, AF_INET6);
|
|
|
|
addrp = &addr;
|
2015-01-03 22:11:23 +01:00
|
|
|
} else if (conn->entry_cfg.ipv4_traffic && !conn->entry_cfg.ipv6_traffic) {
|
2012-11-01 03:04:25 +01:00
|
|
|
tor_addr_make_null(&addr, AF_INET);
|
2011-07-15 18:58:13 +02:00
|
|
|
addrp = &addr;
|
|
|
|
}
|
2016-07-28 16:22:10 +02:00
|
|
|
r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,
|
|
|
|
exit_node);
|
2008-09-23 22:25:01 +02:00
|
|
|
if (r == ADDR_POLICY_REJECTED)
|
|
|
|
return 0; /* We know the address, and the exit policy rejects it. */
|
|
|
|
if (r == ADDR_POLICY_PROBABLY_REJECTED && !conn->chosen_exit_name)
|
|
|
|
return 0; /* We don't know the addr, but the exit policy rejects most
|
|
|
|
* addresses with this port. Since the user didn't ask for
|
|
|
|
* this node, err on the side of caution. */
|
2006-12-13 01:28:56 +01:00
|
|
|
} else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) {
|
2006-09-21 23:48:42 +02:00
|
|
|
/* Don't send DNS requests to non-exit servers by default. */
|
2016-07-28 16:22:10 +02:00
|
|
|
if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit_node))
|
2006-09-21 23:48:42 +02:00
|
|
|
return 0;
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
2016-07-28 16:22:10 +02:00
|
|
|
if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit_node)) {
|
2011-04-27 01:55:34 +02:00
|
|
|
/* Not a suitable exit. Refuse it. */
|
2009-09-20 03:52:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-21 05:16:24 +02:00
|
|
|
return 1;
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
|
|
|
|
2004-11-29 09:34:54 +01:00
|
|
|
/** If address is of the form "y.onion" with a well-formed handle y:
|
2005-10-06 06:33:40 +02:00
|
|
|
* Put a NUL after y, lower-case it, and return ONION_HOSTNAME.
|
2004-11-29 09:34:54 +01:00
|
|
|
*
|
2012-07-06 15:31:47 +02:00
|
|
|
* If address is of the form "x.y.onion" with a well-formed handle x:
|
|
|
|
* Drop "x.", put a NUL after y, lower-case it, and return ONION_HOSTNAME.
|
|
|
|
*
|
2012-01-11 21:55:21 +01:00
|
|
|
* If address is of the form "y.onion" with a badly-formed handle y:
|
|
|
|
* Return BAD_HOSTNAME and log a message.
|
|
|
|
*
|
2012-05-11 23:00:41 +02:00
|
|
|
* If address is of the form "y.exit":
|
2005-10-06 06:33:40 +02:00
|
|
|
* Put a NUL after y and return EXIT_HOSTNAME.
|
2004-11-29 09:34:54 +01:00
|
|
|
*
|
|
|
|
* Otherwise:
|
2004-11-30 04:44:10 +01:00
|
|
|
* Return NORMAL_HOSTNAME and change nothing.
|
2004-11-29 09:34:54 +01:00
|
|
|
*/
|
2004-11-30 04:44:10 +01:00
|
|
|
hostname_type_t
|
2012-05-11 23:00:41 +02:00
|
|
|
parse_extended_hostname(char *address)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-11-29 09:34:54 +01:00
|
|
|
char *s;
|
2012-07-06 15:31:47 +02:00
|
|
|
char *q;
|
2007-11-29 16:25:04 +01:00
|
|
|
char query[REND_SERVICE_ID_LEN_BASE32+1];
|
2004-11-29 09:34:54 +01:00
|
|
|
|
|
|
|
s = strrchr(address,'.');
|
2006-10-09 04:35:51 +02:00
|
|
|
if (!s)
|
|
|
|
return NORMAL_HOSTNAME; /* no dot, thus normal */
|
2005-02-22 01:53:08 +01:00
|
|
|
if (!strcmp(s+1,"exit")) {
|
2012-05-11 23:00:41 +02:00
|
|
|
*s = 0; /* NUL-terminate it */
|
|
|
|
return EXIT_HOSTNAME; /* .exit */
|
2004-11-29 09:34:54 +01:00
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
if (strcmp(s+1,"onion"))
|
2004-11-30 04:44:10 +01:00
|
|
|
return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
|
2004-11-29 09:34:54 +01:00
|
|
|
|
|
|
|
/* so it is .onion */
|
2009-05-27 23:55:51 +02:00
|
|
|
*s = 0; /* NUL-terminate it */
|
2012-07-06 15:31:47 +02:00
|
|
|
/* locate a 'sub-domain' component, in order to remove it */
|
|
|
|
q = strrchr(address, '.');
|
|
|
|
if (q == address) {
|
|
|
|
goto failed; /* reject sub-domain, as DNS does */
|
|
|
|
}
|
|
|
|
q = (NULL == q) ? address : q + 1;
|
|
|
|
if (strlcpy(query, q, REND_SERVICE_ID_LEN_BASE32+1) >=
|
2007-11-29 16:25:04 +01:00
|
|
|
REND_SERVICE_ID_LEN_BASE32+1)
|
2004-11-29 09:34:54 +01:00
|
|
|
goto failed;
|
2012-07-06 15:31:47 +02:00
|
|
|
if (q != address) {
|
|
|
|
memmove(address, q, strlen(q) + 1 /* also get \0 */);
|
|
|
|
}
|
2004-11-29 09:34:54 +01:00
|
|
|
if (rend_valid_service_id(query)) {
|
2004-11-30 04:44:10 +01:00
|
|
|
return ONION_HOSTNAME; /* success */
|
2004-11-29 09:34:54 +01:00
|
|
|
}
|
2010-08-16 00:29:27 +02:00
|
|
|
failed:
|
2004-11-29 09:34:54 +01:00
|
|
|
/* otherwise, return to previous state and return 0 */
|
|
|
|
*s = '.';
|
2012-01-11 21:55:21 +01:00
|
|
|
log_warn(LD_APP, "Invalid onion hostname %s; rejecting",
|
|
|
|
safe_str_client(address));
|
2005-06-07 20:01:46 +02:00
|
|
|
return BAD_HOSTNAME;
|
2004-11-29 09:34:54 +01:00
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|
2011-08-04 18:03:31 +02:00
|
|
|
/** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at
|
|
|
|
* <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory
|
|
|
|
* at <b>b</b>. */
|
|
|
|
static int
|
|
|
|
memeq_opt(const char *a, size_t alen, const char *b, size_t blen)
|
|
|
|
{
|
|
|
|
if (a == NULL) {
|
|
|
|
return (b == NULL);
|
|
|
|
} else if (b == NULL) {
|
|
|
|
return 0;
|
|
|
|
} else if (alen != blen) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return tor_memeq(a, b, alen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-06 22:03:47 +02:00
|
|
|
/**
|
|
|
|
* Return true iff none of the isolation flags and fields in <b>conn</b>
|
|
|
|
* should prevent it from being attached to <b>circ</b>.
|
|
|
|
*/
|
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_edge_compatible_with_circuit(const entry_connection_t *conn,
|
2011-07-06 22:03:47 +02:00
|
|
|
const origin_circuit_t *circ)
|
|
|
|
{
|
2015-01-03 22:11:23 +01:00
|
|
|
const uint8_t iso = conn->entry_cfg.isolation_flags;
|
2011-08-04 18:03:31 +02:00
|
|
|
const socks_request_t *sr = conn->socks_request;
|
2011-07-06 22:03:47 +02:00
|
|
|
|
|
|
|
/* If circ has never been used for an isolated connection, we can
|
|
|
|
* totally use it for this one. */
|
|
|
|
if (!circ->isolation_values_set)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* If circ has been used for connections having more than one value
|
|
|
|
* for some field f, it will have the corresponding bit set in
|
|
|
|
* isolation_flags_mixed. If isolation_flags_mixed has any bits
|
|
|
|
* in common with iso, then conn must be isolated from at least
|
|
|
|
* one stream that has been attached to circ. */
|
|
|
|
if ((iso & circ->isolation_flags_mixed) != 0) {
|
|
|
|
/* For at least one field where conn is isolated, the circuit
|
|
|
|
* already has mixed streams. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-08 21:15:59 +02:00
|
|
|
if (! conn->original_dest_address) {
|
|
|
|
log_warn(LD_BUG, "Reached connection_edge_compatible_with_circuit without "
|
|
|
|
"having set conn->original_dest_address");
|
2011-07-20 18:55:42 +02:00
|
|
|
((entry_connection_t*)conn)->original_dest_address =
|
2011-07-08 21:15:59 +02:00
|
|
|
tor_strdup(conn->socks_request->address);
|
|
|
|
}
|
|
|
|
|
2011-08-06 22:42:32 +02:00
|
|
|
if ((iso & ISO_STREAM) &&
|
|
|
|
(circ->associated_isolated_stream_global_id !=
|
2011-09-07 20:13:57 +02:00
|
|
|
ENTRY_TO_CONN(conn)->global_identifier))
|
2011-07-08 21:54:30 +02:00
|
|
|
return 0;
|
|
|
|
|
2011-07-06 22:03:47 +02:00
|
|
|
if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port)
|
|
|
|
return 0;
|
|
|
|
if ((iso & ISO_DESTADDR) &&
|
2011-07-08 21:15:59 +02:00
|
|
|
strcasecmp(conn->original_dest_address, circ->dest_address))
|
2011-07-06 22:03:47 +02:00
|
|
|
return 0;
|
|
|
|
if ((iso & ISO_SOCKSAUTH) &&
|
2011-08-04 18:03:31 +02:00
|
|
|
(! memeq_opt(sr->username, sr->usernamelen,
|
|
|
|
circ->socks_username, circ->socks_username_len) ||
|
|
|
|
! memeq_opt(sr->password, sr->passwordlen,
|
|
|
|
circ->socks_password, circ->socks_password_len)))
|
2011-07-06 22:03:47 +02:00
|
|
|
return 0;
|
|
|
|
if ((iso & ISO_CLIENTPROTO) &&
|
2011-08-02 16:48:39 +02:00
|
|
|
(conn->socks_request->listener_type != circ->client_proto_type ||
|
2011-07-06 22:03:47 +02:00
|
|
|
conn->socks_request->socks_version != circ->client_proto_socksver))
|
|
|
|
return 0;
|
|
|
|
if ((iso & ISO_CLIENTADDR) &&
|
2011-07-20 18:55:42 +02:00
|
|
|
!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
|
2011-07-06 22:03:47 +02:00
|
|
|
return 0;
|
2015-01-19 17:56:03 +01:00
|
|
|
if ((iso & ISO_SESSIONGRP) &&
|
|
|
|
conn->entry_cfg.session_group != circ->session_group)
|
2011-07-06 22:03:47 +02:00
|
|
|
return 0;
|
2011-07-06 22:39:54 +02:00
|
|
|
if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch)
|
|
|
|
return 0;
|
2011-07-06 22:03:47 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If <b>dry_run</b> is false, update <b>circ</b>'s isolation flags and fields
|
|
|
|
* to reflect having had <b>conn</b> attached to it, and return 0. Otherwise,
|
|
|
|
* if <b>dry_run</b> is true, then make no changes to <b>circ</b>, and return
|
|
|
|
* a bitfield of isolation flags that we would have to set in
|
|
|
|
* isolation_flags_mixed to add <b>conn</b> to <b>circ</b>, or -1 if
|
|
|
|
* <b>circ</b> has had no streams attached to it.
|
|
|
|
*/
|
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_edge_update_circuit_isolation(const entry_connection_t *conn,
|
2011-07-06 22:03:47 +02:00
|
|
|
origin_circuit_t *circ,
|
|
|
|
int dry_run)
|
|
|
|
{
|
2011-08-04 18:03:31 +02:00
|
|
|
const socks_request_t *sr = conn->socks_request;
|
2011-07-08 21:15:59 +02:00
|
|
|
if (! conn->original_dest_address) {
|
|
|
|
log_warn(LD_BUG, "Reached connection_update_circuit_isolation without "
|
|
|
|
"having set conn->original_dest_address");
|
2011-07-20 18:55:42 +02:00
|
|
|
((entry_connection_t*)conn)->original_dest_address =
|
2011-07-08 21:15:59 +02:00
|
|
|
tor_strdup(conn->socks_request->address);
|
|
|
|
}
|
|
|
|
|
2011-07-06 22:03:47 +02:00
|
|
|
if (!circ->isolation_values_set) {
|
|
|
|
if (dry_run)
|
|
|
|
return -1;
|
2011-08-06 22:42:32 +02:00
|
|
|
circ->associated_isolated_stream_global_id =
|
2011-09-07 20:13:57 +02:00
|
|
|
ENTRY_TO_CONN(conn)->global_identifier;
|
2011-07-06 22:03:47 +02:00
|
|
|
circ->dest_port = conn->socks_request->port;
|
2011-07-08 21:15:59 +02:00
|
|
|
circ->dest_address = tor_strdup(conn->original_dest_address);
|
2011-08-02 16:48:39 +02:00
|
|
|
circ->client_proto_type = conn->socks_request->listener_type;
|
2011-07-06 22:03:47 +02:00
|
|
|
circ->client_proto_socksver = conn->socks_request->socks_version;
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr);
|
2015-01-03 22:11:23 +01:00
|
|
|
circ->session_group = conn->entry_cfg.session_group;
|
2011-07-06 22:39:54 +02:00
|
|
|
circ->nym_epoch = conn->nym_epoch;
|
2011-08-04 18:03:31 +02:00
|
|
|
circ->socks_username = sr->username ?
|
|
|
|
tor_memdup(sr->username, sr->usernamelen) : NULL;
|
|
|
|
circ->socks_password = sr->password ?
|
|
|
|
tor_memdup(sr->password, sr->passwordlen) : NULL;
|
|
|
|
circ->socks_username_len = sr->usernamelen;
|
|
|
|
circ->socks_password_len = sr->passwordlen;
|
2011-07-06 22:03:47 +02:00
|
|
|
|
|
|
|
circ->isolation_values_set = 1;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
uint8_t mixed = 0;
|
|
|
|
if (conn->socks_request->port != circ->dest_port)
|
|
|
|
mixed |= ISO_DESTPORT;
|
2011-07-08 21:15:59 +02:00
|
|
|
if (strcasecmp(conn->original_dest_address, circ->dest_address))
|
2011-07-06 22:03:47 +02:00
|
|
|
mixed |= ISO_DESTADDR;
|
2011-08-04 18:03:31 +02:00
|
|
|
if (!memeq_opt(sr->username, sr->usernamelen,
|
|
|
|
circ->socks_username, circ->socks_username_len) ||
|
|
|
|
!memeq_opt(sr->password, sr->passwordlen,
|
|
|
|
circ->socks_password, circ->socks_password_len))
|
2011-07-19 08:36:59 +02:00
|
|
|
mixed |= ISO_SOCKSAUTH;
|
2011-08-02 16:48:39 +02:00
|
|
|
if ((conn->socks_request->listener_type != circ->client_proto_type ||
|
2011-07-06 22:03:47 +02:00
|
|
|
conn->socks_request->socks_version != circ->client_proto_socksver))
|
|
|
|
mixed |= ISO_CLIENTPROTO;
|
2011-07-20 18:55:42 +02:00
|
|
|
if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
|
2011-07-06 22:03:47 +02:00
|
|
|
mixed |= ISO_CLIENTADDR;
|
2015-01-03 22:11:23 +01:00
|
|
|
if (conn->entry_cfg.session_group != circ->session_group)
|
2011-07-06 22:03:47 +02:00
|
|
|
mixed |= ISO_SESSIONGRP;
|
2011-07-06 22:39:54 +02:00
|
|
|
if (conn->nym_epoch != circ->nym_epoch)
|
|
|
|
mixed |= ISO_NYM_EPOCH;
|
2011-07-06 22:03:47 +02:00
|
|
|
|
|
|
|
if (dry_run)
|
|
|
|
return mixed;
|
|
|
|
|
2015-01-03 22:11:23 +01:00
|
|
|
if ((mixed & conn->entry_cfg.isolation_flags) != 0) {
|
2011-08-06 09:25:07 +02:00
|
|
|
log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
|
2011-07-06 22:03:47 +02:00
|
|
|
"isolation flags.");
|
|
|
|
}
|
|
|
|
circ->isolation_flags_mixed |= mixed;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Launch sufficient circuits to satisfy pending isolated streams
Our old "do we need to launch a circuit for stream S" logic was,
more or less, that if we had a pending circuit that could handle S,
we didn't need to launch a new one.
But now that we have streams isolated from one another, we need
something stronger here: It's possible that some pending C can
handle either S1 or S2, but not both.
This patch reuses the existing isolation logic for a simple
solution: when we decide during circuit launching that some pending
C would satisfy stream S1, we "hypothetically" mark C as though S1
had been connected to it. Now if S2 is incompatible with S1, it
won't be something that can attach to C, and so we'll launch a new
stream.
When the circuit becomes OPEN for the first time (with no streams
attached to it), we reset the circuit's isolation status. I'm not
too sure about this part: I wanted some way to be sure that, if all
streams that would have used a circuit die before the circuit is
done, the circuit can still get used. But I worry that this
approach could also lead to us launching too many circuits. Careful
thought needed here.
2011-07-07 16:40:23 +02:00
|
|
|
/**
|
|
|
|
* Clear the isolation settings on <b>circ</b>.
|
|
|
|
*
|
|
|
|
* This only works on an open circuit that has never had a stream attached to
|
|
|
|
* it, and whose isolation settings are hypothetical. (We set hypothetical
|
|
|
|
* isolation settings on circuits as we're launching them, so that we
|
|
|
|
* know whether they can handle more streams or whether we need to launch
|
2011-07-19 19:51:43 +02:00
|
|
|
* even more circuits. Once the circuit is open, if it turns out that
|
|
|
|
* we no longer have any streams to attach to it, we clear the isolation flags
|
|
|
|
* and data so that other streams can have a chance.)
|
Launch sufficient circuits to satisfy pending isolated streams
Our old "do we need to launch a circuit for stream S" logic was,
more or less, that if we had a pending circuit that could handle S,
we didn't need to launch a new one.
But now that we have streams isolated from one another, we need
something stronger here: It's possible that some pending C can
handle either S1 or S2, but not both.
This patch reuses the existing isolation logic for a simple
solution: when we decide during circuit launching that some pending
C would satisfy stream S1, we "hypothetically" mark C as though S1
had been connected to it. Now if S2 is incompatible with S1, it
won't be something that can attach to C, and so we'll launch a new
stream.
When the circuit becomes OPEN for the first time (with no streams
attached to it), we reset the circuit's isolation status. I'm not
too sure about this part: I wanted some way to be sure that, if all
streams that would have used a circuit die before the circuit is
done, the circuit can still get used. But I worry that this
approach could also lead to us launching too many circuits. Careful
thought needed here.
2011-07-07 16:40:23 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
circuit_clear_isolation(origin_circuit_t *circ)
|
|
|
|
{
|
|
|
|
if (circ->isolation_any_streams_attached) {
|
|
|
|
log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) {
|
|
|
|
log_warn(LD_BUG, "Tried to clear the isolation status of a non-open "
|
|
|
|
"circuit");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
circ->isolation_values_set = 0;
|
|
|
|
circ->isolation_flags_mixed = 0;
|
2011-08-06 22:42:32 +02:00
|
|
|
circ->associated_isolated_stream_global_id = 0;
|
Launch sufficient circuits to satisfy pending isolated streams
Our old "do we need to launch a circuit for stream S" logic was,
more or less, that if we had a pending circuit that could handle S,
we didn't need to launch a new one.
But now that we have streams isolated from one another, we need
something stronger here: It's possible that some pending C can
handle either S1 or S2, but not both.
This patch reuses the existing isolation logic for a simple
solution: when we decide during circuit launching that some pending
C would satisfy stream S1, we "hypothetically" mark C as though S1
had been connected to it. Now if S2 is incompatible with S1, it
won't be something that can attach to C, and so we'll launch a new
stream.
When the circuit becomes OPEN for the first time (with no streams
attached to it), we reset the circuit's isolation status. I'm not
too sure about this part: I wanted some way to be sure that, if all
streams that would have used a circuit die before the circuit is
done, the circuit can still get used. But I worry that this
approach could also lead to us launching too many circuits. Careful
thought needed here.
2011-07-07 16:40:23 +02:00
|
|
|
circ->client_proto_type = 0;
|
|
|
|
circ->client_proto_socksver = 0;
|
|
|
|
circ->dest_port = 0;
|
|
|
|
tor_addr_make_unspec(&circ->client_addr);
|
|
|
|
tor_free(circ->dest_address);
|
|
|
|
circ->session_group = -1;
|
|
|
|
circ->nym_epoch = 0;
|
2011-08-06 01:07:33 +02:00
|
|
|
if (circ->socks_username) {
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(circ->socks_username, 0x11, circ->socks_username_len);
|
2011-08-06 01:07:33 +02:00
|
|
|
tor_free(circ->socks_username);
|
|
|
|
}
|
|
|
|
if (circ->socks_password) {
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(circ->socks_password, 0x05, circ->socks_password_len);
|
2011-08-06 01:07:33 +02:00
|
|
|
tor_free(circ->socks_password);
|
|
|
|
}
|
2011-08-04 18:03:31 +02:00
|
|
|
circ->socks_username_len = circ->socks_password_len = 0;
|
Launch sufficient circuits to satisfy pending isolated streams
Our old "do we need to launch a circuit for stream S" logic was,
more or less, that if we had a pending circuit that could handle S,
we didn't need to launch a new one.
But now that we have streams isolated from one another, we need
something stronger here: It's possible that some pending C can
handle either S1 or S2, but not both.
This patch reuses the existing isolation logic for a simple
solution: when we decide during circuit launching that some pending
C would satisfy stream S1, we "hypothetically" mark C as though S1
had been connected to it. Now if S2 is incompatible with S1, it
won't be something that can attach to C, and so we'll launch a new
stream.
When the circuit becomes OPEN for the first time (with no streams
attached to it), we reset the circuit's isolation status. I'm not
too sure about this part: I wanted some way to be sure that, if all
streams that would have used a circuit die before the circuit is
done, the circuit can still get used. But I worry that this
approach could also lead to us launching too many circuits. Careful
thought needed here.
2011-07-07 16:40:23 +02:00
|
|
|
}
|
|
|
|
|
2015-11-17 15:06:47 +01:00
|
|
|
/** Free all storage held in module-scoped variables for connection_edge.c */
|
|
|
|
void
|
|
|
|
connection_edge_free_all(void)
|
|
|
|
{
|
|
|
|
untried_pending_connections = 0;
|
|
|
|
smartlist_free(pending_entry_connections);
|
|
|
|
pending_entry_connections = NULL;
|
|
|
|
}
|
2015-11-20 16:52:56 +01:00
|
|
|
|