2006-02-09 06:46:49 +01:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
2007-12-12 22:09:01 +01:00
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2012-06-05 02:58:17 +02:00
|
|
|
* Copyright (c) 2007-2012, 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.
|
2004-05-10 06:42:22 +02:00
|
|
|
**/
|
|
|
|
|
2003-04-12 00:11:11 +02:00
|
|
|
#include "or.h"
|
2010-07-22 00:46:18 +02:00
|
|
|
#include "buffers.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"
|
2010-07-22 12:09:49 +02:00
|
|
|
#include "dirserv.h"
|
2010-07-22 12:30:46 +02:00
|
|
|
#include "hibernate.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"
|
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
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/pfvar.h>
|
|
|
|
#define TRANS_PF
|
|
|
|
#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);
|
2007-10-02 22:35:23 +02:00
|
|
|
static int address_is_in_virtual_range(const char *addr);
|
2011-07-20 18:55:42 +02:00
|
|
|
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
|
2008-02-21 19:45:11 +01:00
|
|
|
static void clear_trackexithost_mappings(const char *exitname);
|
2011-07-20 18:55:42 +02:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
void
|
2011-07-20 18:55:42 +02:00
|
|
|
_connection_mark_unattached_ap(entry_connection_t *conn, int endreason,
|
2005-06-11 20:52:12 +02:00
|
|
|
int line, const char *file)
|
|
|
|
{
|
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)) {
|
|
|
|
rend_client_note_connection_attempt_ended(
|
|
|
|
edge_conn->rend_data->onion_address);
|
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. */
|
2011-07-20 18:55:42 +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
|
|
|
|
2011-07-20 18:55:42 +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;
|
|
|
|
}
|
2006-07-26 21:07:26 +02:00
|
|
|
log_info(LD_EDGE,"conn (fd %d) reached eof. Closing.", conn->_base.s);
|
|
|
|
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);
|
2011-07-20 18:55:42 +02:00
|
|
|
if (conn->_base.type == CONN_TYPE_AP) {
|
|
|
|
/* 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
|
|
|
|
2006-07-26 21:07:26 +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",
|
|
|
|
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. */
|
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.",
|
2006-07-26 21:07:26 +02:00
|
|
|
conn_state_to_string(conn->_base.type, conn->_base.state));
|
2003-04-12 00:11:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2007-03-04 21:11:46 +01: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
|
|
|
{
|
2006-07-26 21:07:26 +02:00
|
|
|
if (!conn->_base.marked_for_close) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_EDGE,
|
|
|
|
"CircID %d: At an edge. Marking connection for close.", circ_id);
|
2006-07-26 21:07:26 +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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** 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
|
|
|
}
|
|
|
|
|
2006-07-26 21:07:26 +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.",
|
2006-07-26 21:07:26 +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;
|
|
|
|
if (tor_addr_family(&conn->_base.addr) == AF_INET) {
|
|
|
|
set_uint32(payload+1, tor_addr_to_ipv4n(&conn->_base.addr));
|
|
|
|
addrlen = 4;
|
|
|
|
} else {
|
|
|
|
memcpy(payload+1, tor_addr_to_in6_addr8(&conn->_base.addr), 16);
|
|
|
|
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) {
|
2007-02-13 22:18:56 +01:00
|
|
|
log_debug(LD_EDGE,"Sending end on conn (fd %d).",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);
|
2004-02-27 23:00:26 +01:00
|
|
|
} else {
|
2007-02-13 22:18:56 +01:00
|
|
|
log_debug(LD_EDGE,"No circ to send end on conn (fd %d).",
|
2006-07-26 21:07:26 +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);
|
2008-06-11 03:14:23 +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)
|
|
|
|
{
|
|
|
|
switch (conn->_base.state) {
|
|
|
|
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
|
|
|
|
2006-07-26 21:07:26 +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:
|
2007-03-04 21:11:46 +01: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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
tor_assert(edge_conn->_base.type == CONN_TYPE_EXIT);
|
|
|
|
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,
|
2009-02-10 19:52:47 +01:00
|
|
|
safe_str(fmt_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;
|
2009-08-11 21:16:16 +02:00
|
|
|
IF_HAS_NO_BUFFEREVENT(conn)
|
|
|
|
connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
|
|
|
|
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 {
|
2008-08-05 22:08:19 +02:00
|
|
|
char connected_payload[20];
|
|
|
|
int connected_payload_len;
|
|
|
|
if (tor_addr_family(&conn->addr) == AF_INET) {
|
|
|
|
set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
|
|
|
|
set_uint32(connected_payload+4,
|
|
|
|
htonl(dns_clip_ttl(edge_conn->address_ttl)));
|
|
|
|
connected_payload_len = 8;
|
|
|
|
} else {
|
|
|
|
memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
|
|
|
|
set_uint32(connected_payload+16,
|
|
|
|
htonl(dns_clip_ttl(edge_conn->address_ttl)));
|
|
|
|
connected_payload_len = 20;
|
|
|
|
}
|
2006-07-26 21:07:26 +02:00
|
|
|
if (connection_edge_send_command(edge_conn,
|
2008-08-05 22:08:19 +02:00
|
|
|
RELAY_COMMAND_CONNECTED,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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
|
|
|
}
|
|
|
|
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));
|
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;
|
|
|
|
}
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
|
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;
|
2004-12-04 04:26:35 +01:00
|
|
|
/* kludge to make us not try this circuit again, yet to allow
|
|
|
|
* current streams on it to survive if they can: make it
|
|
|
|
* unattractive to use for new streams */
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024 this is a kludgy way to do this. */
|
2004-12-04 04:26:35 +01:00
|
|
|
tor_assert(circ->timestamp_dirty);
|
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
|
|
|
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
|
2006-07-18 06:42:32 +02:00
|
|
|
/* give our stream another 'cutoff' seconds to try */
|
2006-07-26 21:07:26 +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
|
|
|
}
|
|
|
|
|
2006-12-10 09:04:50 +01:00
|
|
|
/** Tell any AP streams that are waiting for a new circuit to try again,
|
|
|
|
* either attaching to an available circ or launching a new one.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
connection_ap_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();
|
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;
|
2011-07-20 18:55:42 +02:00
|
|
|
entry_conn = TO_ENTRY_CONN(conn);
|
|
|
|
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
|
|
|
}
|
2012-07-17 15:33:38 +02:00
|
|
|
} SMARTLIST_FOREACH_END(conn);
|
2003-11-11 03:41:31 +01:00
|
|
|
}
|
|
|
|
|
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. */
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXX024 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 ||
|
2011-07-20 18:55:42 +02:00
|
|
|
!entry_conn->socks_request || !entry_conn->socks_request->address)
|
2008-08-05 22:08:19 +02:00
|
|
|
continue;
|
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
|
2005-03-17 13:38:37 +01:00
|
|
|
* new circuit, tell the controller, or give up as a appropriate.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
|
|
|
if (conn->pending_optimistic_data) {
|
|
|
|
generic_buffer_set_to_copy(&conn->sending_optimistic_data,
|
|
|
|
conn->pending_optimistic_data);
|
|
|
|
}
|
|
|
|
|
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));
|
2005-03-14 04:12:59 +01:00
|
|
|
return connection_ap_handshake_attach_circuit(conn);
|
|
|
|
} else {
|
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
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
/** A client-side struct to remember requests to rewrite addresses
|
2005-12-03 17:32:29 +01:00
|
|
|
* to new addresses. These structs are stored in the hash table
|
2005-12-03 03:21:31 +01:00
|
|
|
* "addressmap" below.
|
2005-02-22 01:53:08 +01:00
|
|
|
*
|
|
|
|
* There are 5 ways to set an address mapping:
|
|
|
|
* - A MapAddress command from the controller [permanent]
|
|
|
|
* - An AddressMap directive in the torrc [permanent]
|
|
|
|
* - When a TrackHostExits torrc directive is triggered [temporary]
|
2009-05-27 23:55:51 +02:00
|
|
|
* - When a DNS resolve succeeds [temporary]
|
|
|
|
* - When a DNS resolve fails [temporary]
|
2005-02-22 01:53:08 +01:00
|
|
|
*
|
|
|
|
* When an addressmap request is made but one is already registered,
|
|
|
|
* the new one is replaced only if the currently registered one has
|
2009-05-27 23:55:51 +02:00
|
|
|
* no "new_address" (that is, it's in the process of DNS resolve),
|
2005-03-03 07:37:54 +01:00
|
|
|
* or if the new one is permanent (expires==0 or 1).
|
|
|
|
*
|
|
|
|
* (We overload the 'expires' field, using "0" for mappings set via
|
|
|
|
* the configuration file, "1" for mappings set from the control
|
2008-09-29 16:53:53 +02:00
|
|
|
* interface, and other values for DNS and TrackHostExit mappings that can
|
|
|
|
* expire.)
|
2011-09-08 17:54:24 +02:00
|
|
|
*
|
|
|
|
* A mapping may be 'wildcarded'. If "src_wildcard" is true, then
|
|
|
|
* any address that ends with a . followed by the key for this entry will
|
|
|
|
* get remapped by it. If "dst_wildcard" is also true, then only the
|
|
|
|
* matching suffix of such addresses will get replaced by new_address.
|
2005-02-22 01:53:08 +01:00
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
char *new_address;
|
|
|
|
time_t expires;
|
2008-02-21 19:45:11 +01:00
|
|
|
addressmap_entry_source_t source:3;
|
2011-09-08 17:54:24 +02:00
|
|
|
unsigned src_wildcard:1;
|
|
|
|
unsigned dst_wildcard:1;
|
2008-02-21 19:45:11 +01:00
|
|
|
short num_resolve_failures;
|
2005-02-22 01:53:08 +01:00
|
|
|
} addressmap_entry_t;
|
|
|
|
|
2005-10-06 06:33:40 +02:00
|
|
|
/** Entry for mapping addresses to which virtual address we mapped them to. */
|
2005-03-02 23:01:10 +01:00
|
|
|
typedef struct {
|
|
|
|
char *ipv4_address;
|
|
|
|
char *hostname_address;
|
|
|
|
} virtaddress_entry_t;
|
|
|
|
|
2005-12-03 03:21:31 +01:00
|
|
|
/** A hash table to store client-side address rewrite instructions. */
|
2005-03-23 09:40:11 +01:00
|
|
|
static strmap_t *addressmap=NULL;
|
2005-03-02 23:01:10 +01:00
|
|
|
/**
|
2005-12-03 03:21:31 +01:00
|
|
|
* Table mapping addresses to which virtual address, if any, we
|
2005-03-02 23:01:10 +01:00
|
|
|
* assigned them to.
|
|
|
|
*
|
|
|
|
* We maintain the following invariant: if [A,B] is in
|
|
|
|
* virtaddress_reversemap, then B must be a virtual address, and [A,B]
|
|
|
|
* must be in addressmap. We do not require that the converse hold:
|
|
|
|
* if it fails, then we could end up mapping two virtual addresses to
|
|
|
|
* the same address, which is no disaster.
|
|
|
|
**/
|
2005-03-23 09:40:11 +01:00
|
|
|
static strmap_t *virtaddress_reversemap=NULL;
|
2005-02-22 01:53:08 +01:00
|
|
|
|
|
|
|
/** Initialize addressmap. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
addressmap_init(void)
|
|
|
|
{
|
2005-02-22 01:53:08 +01:00
|
|
|
addressmap = strmap_new();
|
2005-03-02 22:02:11 +01:00
|
|
|
virtaddress_reversemap = strmap_new();
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Free the memory associated with the addressmap entry <b>_ent</b>. */
|
|
|
|
static void
|
2005-06-11 20:52:12 +02:00
|
|
|
addressmap_ent_free(void *_ent)
|
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
if (!_ent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ent = _ent;
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_free(ent->new_address);
|
|
|
|
tor_free(ent);
|
|
|
|
}
|
|
|
|
|
2007-05-25 21:41:31 +02:00
|
|
|
/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
|
2005-03-02 22:02:11 +01:00
|
|
|
static void
|
2005-06-11 20:52:12 +02:00
|
|
|
addressmap_virtaddress_ent_free(void *_ent)
|
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
virtaddress_entry_t *ent;
|
|
|
|
if (!_ent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ent = _ent;
|
2005-03-02 23:01:10 +01:00
|
|
|
tor_free(ent->ipv4_address);
|
|
|
|
tor_free(ent->hostname_address);
|
|
|
|
tor_free(ent);
|
|
|
|
}
|
|
|
|
|
2007-05-25 21:41:31 +02:00
|
|
|
/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
|
2005-03-02 23:01:10 +01:00
|
|
|
static void
|
2005-10-05 04:06:36 +02:00
|
|
|
addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
|
2005-03-02 22:02:11 +01:00
|
|
|
{
|
2005-12-14 21:40:40 +01:00
|
|
|
if (ent && ent->new_address &&
|
|
|
|
address_is_in_virtual_range(ent->new_address)) {
|
2005-03-02 23:01:10 +01:00
|
|
|
virtaddress_entry_t *ve =
|
|
|
|
strmap_get(virtaddress_reversemap, ent->new_address);
|
2005-03-23 09:40:11 +01:00
|
|
|
/*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
|
2005-03-02 23:01:10 +01:00
|
|
|
if (ve) {
|
2005-10-05 04:06:36 +02:00
|
|
|
if (!strcmp(address, ve->ipv4_address))
|
2005-03-02 23:01:10 +01:00
|
|
|
tor_free(ve->ipv4_address);
|
2005-10-05 04:06:36 +02:00
|
|
|
if (!strcmp(address, ve->hostname_address))
|
2005-03-02 23:01:10 +01:00
|
|
|
tor_free(ve->hostname_address);
|
|
|
|
if (!ve->ipv4_address && !ve->hostname_address) {
|
|
|
|
tor_free(ve);
|
|
|
|
strmap_remove(virtaddress_reversemap, ent->new_address);
|
|
|
|
}
|
2005-03-02 22:02:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-02 19:58:11 +01:00
|
|
|
/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
|
|
|
|
* client address maps. */
|
2005-03-02 23:01:10 +01:00
|
|
|
static void
|
2005-10-05 04:06:36 +02:00
|
|
|
addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
|
2005-03-02 23:01:10 +01:00
|
|
|
{
|
2005-10-05 04:06:36 +02:00
|
|
|
addressmap_virtaddress_remove(address, ent);
|
2005-03-02 23:01:10 +01:00
|
|
|
addressmap_ent_free(ent);
|
|
|
|
}
|
2005-03-02 22:02:11 +01:00
|
|
|
|
2008-02-21 19:45:11 +01:00
|
|
|
/** Unregister all TrackHostExits mappings from any address to
|
|
|
|
* *.exitname.exit. */
|
|
|
|
static void
|
|
|
|
clear_trackexithost_mappings(const char *exitname)
|
|
|
|
{
|
2012-01-11 20:02:59 +01:00
|
|
|
char *suffix = NULL;
|
2008-02-21 19:45:11 +01:00
|
|
|
if (!addressmap || !exitname)
|
|
|
|
return;
|
2012-01-11 20:02:59 +01:00
|
|
|
tor_asprintf(&suffix, ".%s.exit", exitname);
|
2008-02-21 19:45:11 +01:00
|
|
|
tor_strlower(suffix);
|
|
|
|
|
|
|
|
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
|
2011-04-27 23:21:41 +02:00
|
|
|
if (ent->source == ADDRMAPSRC_TRACKEXIT &&
|
|
|
|
!strcmpend(ent->new_address, suffix)) {
|
2008-02-21 19:45:11 +01:00
|
|
|
addressmap_ent_remove(address, ent);
|
|
|
|
MAP_DEL_CURRENT(address);
|
|
|
|
}
|
|
|
|
} STRMAP_FOREACH_END;
|
2008-09-05 22:52:15 +02:00
|
|
|
|
|
|
|
tor_free(suffix);
|
2008-02-21 19:45:11 +01:00
|
|
|
}
|
|
|
|
|
2011-04-04 01:43:47 +02:00
|
|
|
/** Remove all TRACKEXIT mappings from the addressmap for which the target
|
2011-05-13 22:22:58 +02:00
|
|
|
* host is unknown or no longer allowed, or for which the source address
|
|
|
|
* is no longer in trackexithosts. */
|
2011-04-04 01:43:47 +02:00
|
|
|
void
|
2011-06-14 19:01:38 +02:00
|
|
|
addressmap_clear_excluded_trackexithosts(const or_options_t *options)
|
2011-04-04 01:43:47 +02:00
|
|
|
{
|
|
|
|
const routerset_t *allow_nodes = options->ExitNodes;
|
|
|
|
const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
|
|
|
|
|
|
|
|
if (!addressmap)
|
|
|
|
return;
|
|
|
|
if (routerset_is_empty(allow_nodes))
|
|
|
|
allow_nodes = NULL;
|
|
|
|
if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
|
|
|
|
return;
|
|
|
|
|
|
|
|
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
|
|
|
|
size_t len;
|
|
|
|
const char *target = ent->new_address, *dot;
|
|
|
|
char *nodename;
|
2011-04-27 20:36:30 +02:00
|
|
|
const node_t *node;
|
2011-04-04 01:43:47 +02:00
|
|
|
|
2011-10-20 05:14:05 +02:00
|
|
|
if (!target) {
|
|
|
|
/* DNS resolving in progress */
|
|
|
|
continue;
|
|
|
|
} else if (strcmpend(target, ".exit")) {
|
2011-04-04 01:43:47 +02:00
|
|
|
/* Not a .exit mapping */
|
|
|
|
continue;
|
|
|
|
} else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
|
|
|
|
/* Not a trackexit mapping. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
len = strlen(target);
|
|
|
|
if (len < 6)
|
|
|
|
continue; /* malformed. */
|
|
|
|
dot = target + len - 6; /* dot now points to just before .exit */
|
2011-09-08 02:26:58 +02:00
|
|
|
while (dot > target && *dot != '.')
|
|
|
|
dot--;
|
2011-09-07 02:26:20 +02:00
|
|
|
if (*dot == '.') dot++;
|
|
|
|
nodename = tor_strndup(dot, len-5-(dot-target));;
|
2011-04-27 20:36:30 +02:00
|
|
|
node = node_get_by_nickname(nodename, 0);
|
2011-04-04 01:43:47 +02:00
|
|
|
tor_free(nodename);
|
2011-04-27 20:36:30 +02:00
|
|
|
if (!node ||
|
|
|
|
(allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
|
2011-05-15 17:44:51 +02:00
|
|
|
routerset_contains_node(exclude_nodes, node) ||
|
2011-05-13 22:22:58 +02:00
|
|
|
!hostname_in_track_host_exits(options, address)) {
|
2011-04-04 01:43:47 +02:00
|
|
|
/* We don't know this one, or we want to be rid of it. */
|
|
|
|
addressmap_ent_remove(address, ent);
|
|
|
|
MAP_DEL_CURRENT(address);
|
|
|
|
}
|
|
|
|
} STRMAP_FOREACH_END;
|
|
|
|
}
|
|
|
|
|
2011-05-13 22:59:31 +02:00
|
|
|
/** Remove all AUTOMAP mappings from the addressmap for which the
|
|
|
|
* source address no longer matches AutomapHostsSuffixes, which is
|
|
|
|
* no longer allowed by AutomapHostsOnResolve, or for which the
|
|
|
|
* target address is no longer in the virtual network. */
|
|
|
|
void
|
2011-06-14 19:01:38 +02:00
|
|
|
addressmap_clear_invalid_automaps(const or_options_t *options)
|
2011-05-13 22:59:31 +02:00
|
|
|
{
|
|
|
|
int clear_all = !options->AutomapHostsOnResolve;
|
|
|
|
const smartlist_t *suffixes = options->AutomapHostsSuffixes;
|
|
|
|
|
|
|
|
if (!addressmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!suffixes)
|
|
|
|
clear_all = 1; /* This should be impossible, but let's be sure. */
|
|
|
|
|
|
|
|
STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
|
|
|
|
int remove = clear_all;
|
|
|
|
if (ent->source != ADDRMAPSRC_AUTOMAP)
|
|
|
|
continue; /* not an automap mapping. */
|
|
|
|
|
|
|
|
if (!remove) {
|
|
|
|
int suffix_found = 0;
|
|
|
|
SMARTLIST_FOREACH(suffixes, const char *, suffix, {
|
|
|
|
if (!strcasecmpend(src_address, suffix)) {
|
|
|
|
suffix_found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (!suffix_found)
|
|
|
|
remove = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!remove && ! address_is_in_virtual_range(ent->new_address))
|
|
|
|
remove = 1;
|
|
|
|
|
|
|
|
if (remove) {
|
|
|
|
addressmap_ent_remove(src_address, ent);
|
|
|
|
MAP_DEL_CURRENT(src_address);
|
|
|
|
}
|
|
|
|
} STRMAP_FOREACH_END;
|
|
|
|
}
|
|
|
|
|
2005-03-11 22:39:39 +01:00
|
|
|
/** Remove all entries from the addressmap that were set via the
|
|
|
|
* configuration file or the command line. */
|
|
|
|
void
|
|
|
|
addressmap_clear_configured(void)
|
|
|
|
{
|
2007-07-16 18:58:11 +02:00
|
|
|
addressmap_get_mappings(NULL, 0, 0, 0);
|
2005-03-11 22:39:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove all entries from the addressmap that are set to expire, ever. */
|
|
|
|
void
|
|
|
|
addressmap_clear_transient(void)
|
|
|
|
{
|
2007-07-16 18:58:11 +02:00
|
|
|
addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Clean out entries from the addressmap cache that were
|
|
|
|
* added long enough ago that they are no longer valid.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
addressmap_clean(time_t now)
|
|
|
|
{
|
2007-07-16 18:58:11 +02:00
|
|
|
addressmap_get_mappings(NULL, 2, now, 0);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Free all the elements in the addressmap, and free the addressmap
|
|
|
|
* itself. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
addressmap_free_all(void)
|
|
|
|
{
|
2009-12-12 08:07:59 +01:00
|
|
|
strmap_free(addressmap, addressmap_ent_free);
|
|
|
|
addressmap = NULL;
|
|
|
|
|
|
|
|
strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
|
|
|
|
virtaddress_reversemap = NULL;
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
2010-12-13 23:13:01 +01:00
|
|
|
/** Try to find a match for AddressMap expressions that use
|
|
|
|
* wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
|
|
|
|
* '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
|
2011-09-08 17:54:24 +02:00
|
|
|
* Return the matching entry in AddressMap or NULL if no match is found.
|
|
|
|
* For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
|
|
|
|
* to 'a' before we return the matching AddressMap entry.
|
|
|
|
*
|
|
|
|
* This function does not handle the case where a pattern of the form "*.c.d"
|
|
|
|
* matches the address c.d -- that's done by the main addressmap_rewrite
|
|
|
|
* function.
|
2010-08-02 21:09:37 +02:00
|
|
|
*/
|
|
|
|
static addressmap_entry_t *
|
|
|
|
addressmap_match_superdomains(char *address)
|
|
|
|
{
|
|
|
|
addressmap_entry_t *val;
|
2011-09-08 17:54:24 +02:00
|
|
|
char *cp;
|
|
|
|
|
|
|
|
cp = address;
|
|
|
|
while ((cp = strchr(cp, '.'))) {
|
|
|
|
/* cp now points to a suffix of address that begins with a . */
|
|
|
|
val = strmap_get_lc(addressmap, cp+1);
|
|
|
|
if (val && val->src_wildcard) {
|
|
|
|
if (val->dst_wildcard)
|
|
|
|
*cp = '\0';
|
|
|
|
return val;
|
2010-08-02 21:09:37 +02:00
|
|
|
}
|
2011-09-08 17:54:24 +02:00
|
|
|
++cp;
|
2010-08-02 21:09:37 +02:00
|
|
|
}
|
2011-09-08 17:54:24 +02:00
|
|
|
return NULL;
|
2010-08-02 21:09:37 +02:00
|
|
|
}
|
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
/** Look at address, and rewrite it until it doesn't want any
|
|
|
|
* more rewrites; but don't get into an infinite loop.
|
2007-02-05 20:15:13 +01:00
|
|
|
* Don't write more than maxlen chars into address. Return true if the
|
2007-07-30 19:46:14 +02:00
|
|
|
* address changed; false otherwise. Set *<b>expires_out</b> to the
|
|
|
|
* expiry time of the result, or to <b>time_max</b> if the result does
|
|
|
|
* not expire.
|
2012-05-11 23:00:41 +02:00
|
|
|
*
|
2012-06-04 23:15:21 +02:00
|
|
|
* If <b>exit_source_out</b> is non-null, we set it as follows. If we the
|
|
|
|
* address starts out as a non-exit address, and we remap it to an .exit
|
|
|
|
* address at any point, then set *<b>exit_source_out</b> to the
|
|
|
|
* address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
|
2012-06-20 01:45:28 +02:00
|
|
|
* to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
|
|
|
|
* was a .exit.
|
2005-02-22 01:53:08 +01:00
|
|
|
*/
|
2007-02-05 20:15:13 +01:00
|
|
|
int
|
2012-05-11 23:00:41 +02:00
|
|
|
addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out,
|
|
|
|
addressmap_entry_source_t *exit_source_out)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2005-02-22 01:53:08 +01:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
int rewrites;
|
2007-07-10 19:14:51 +02:00
|
|
|
time_t expires = TIME_MAX;
|
2012-05-11 23:00:41 +02:00
|
|
|
addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
|
2012-06-20 01:45:28 +02:00
|
|
|
char *addr_orig = tor_strdup(address);
|
|
|
|
char *log_addr_orig = NULL;
|
2005-02-22 01:53:08 +01:00
|
|
|
|
|
|
|
for (rewrites = 0; rewrites < 16; rewrites++) {
|
2011-11-30 20:02:58 +01:00
|
|
|
int exact_match = 0;
|
2012-06-20 01:45:28 +02:00
|
|
|
log_addr_orig = tor_strdup(escaped_safe_str_client(address));
|
2011-11-30 20:02:58 +01:00
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
ent = strmap_get(addressmap, address);
|
|
|
|
|
2007-07-10 19:14:51 +02:00
|
|
|
if (!ent || !ent->new_address) {
|
2010-08-02 21:09:37 +02:00
|
|
|
ent = addressmap_match_superdomains(address);
|
2011-11-30 20:02:58 +01:00
|
|
|
} else {
|
|
|
|
if (ent->src_wildcard && !ent->dst_wildcard &&
|
|
|
|
!strcasecmp(address, ent->new_address)) {
|
|
|
|
/* This is a rule like *.example.com example.com, and we just got
|
|
|
|
* "example.com" */
|
2012-05-11 23:00:41 +02:00
|
|
|
goto done;
|
2011-11-30 20:02:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
exact_match = 1;
|
|
|
|
}
|
2010-08-02 21:09:37 +02:00
|
|
|
|
2007-07-10 19:14:51 +02:00
|
|
|
if (!ent || !ent->new_address) {
|
2012-05-11 23:00:41 +02:00
|
|
|
goto done;
|
2007-07-10 19:14:51 +02:00
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2011-11-30 20:02:58 +01:00
|
|
|
if (ent->dst_wildcard && !exact_match) {
|
2011-09-08 17:54:24 +02:00
|
|
|
strlcat(address, ".", maxlen);
|
|
|
|
strlcat(address, ent->new_address, maxlen);
|
|
|
|
} else {
|
2010-08-02 21:09:37 +02:00
|
|
|
strlcpy(address, ent->new_address, maxlen);
|
2011-09-08 17:54:24 +02:00
|
|
|
}
|
2010-08-02 21:09:37 +02:00
|
|
|
|
2012-05-11 23:00:41 +02:00
|
|
|
if (!strcmpend(address, ".exit") &&
|
|
|
|
strcmpend(addr_orig, ".exit") &&
|
|
|
|
exit_source == ADDRMAPSRC_NONE) {
|
|
|
|
exit_source = ent->source;
|
|
|
|
}
|
|
|
|
|
2007-05-25 20:22:42 +02:00
|
|
|
log_info(LD_APP, "Addressmap: rewriting %s to %s",
|
2012-06-20 01:45:28 +02:00
|
|
|
log_addr_orig, escaped_safe_str_client(address));
|
2007-07-10 19:14:51 +02:00
|
|
|
if (ent->expires > 1 && ent->expires < expires)
|
|
|
|
expires = ent->expires;
|
2012-06-20 01:45:28 +02:00
|
|
|
|
|
|
|
tor_free(log_addr_orig);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_CONFIG,
|
2007-01-04 10:12:23 +01:00
|
|
|
"Loop detected: we've rewritten %s 16 times! Using it as-is.",
|
2009-12-15 23:23:36 +01:00
|
|
|
escaped_safe_str_client(address));
|
2005-02-22 01:53:08 +01:00
|
|
|
/* it's fine to rewrite a rewrite, but don't loop forever */
|
2012-05-11 23:00:41 +02:00
|
|
|
|
|
|
|
done:
|
2012-06-20 01:45:28 +02:00
|
|
|
tor_free(addr_orig);
|
|
|
|
tor_free(log_addr_orig);
|
2012-05-11 23:00:41 +02:00
|
|
|
if (exit_source_out)
|
|
|
|
*exit_source_out = exit_source;
|
2007-07-10 19:14:51 +02:00
|
|
|
if (expires_out)
|
|
|
|
*expires_out = TIME_MAX;
|
2012-05-11 23:00:41 +02:00
|
|
|
return (rewrites > 0);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
2007-02-02 19:58:11 +01:00
|
|
|
/** If we have a cached reverse DNS entry for the address stored in the
|
2007-02-06 03:49:07 +01:00
|
|
|
* <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
|
2007-07-30 19:46:14 +02:00
|
|
|
* rewrite to the cached value and return 1. Otherwise return 0. Set
|
|
|
|
* *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
|
|
|
|
* if the result does not expire. */
|
2006-12-26 23:41:43 +01:00
|
|
|
static int
|
2007-07-10 19:14:51 +02:00
|
|
|
addressmap_rewrite_reverse(char *address, size_t maxlen, time_t *expires_out)
|
2006-12-26 23:41:43 +01:00
|
|
|
{
|
2012-01-11 20:02:59 +01:00
|
|
|
char *s, *cp;
|
2006-12-26 23:41:43 +01:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
int r = 0;
|
2012-01-11 20:02:59 +01:00
|
|
|
tor_asprintf(&s, "REVERSE[%s]", address);
|
2006-12-26 23:41:43 +01:00
|
|
|
ent = strmap_get(addressmap, s);
|
|
|
|
if (ent) {
|
2009-12-15 23:23:36 +01:00
|
|
|
cp = tor_strdup(escaped_safe_str_client(ent->new_address));
|
2007-01-04 10:12:23 +01:00
|
|
|
log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
|
2009-12-15 23:23:36 +01:00
|
|
|
escaped_safe_str_client(s), cp);
|
2006-12-26 23:41:43 +01:00
|
|
|
tor_free(cp);
|
|
|
|
strlcpy(address, ent->new_address, maxlen);
|
|
|
|
r = 1;
|
|
|
|
}
|
2007-07-10 19:14:51 +02:00
|
|
|
|
|
|
|
if (expires_out)
|
|
|
|
*expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
|
|
|
|
|
2006-12-26 23:41:43 +01:00
|
|
|
tor_free(s);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2008-09-29 16:53:53 +02:00
|
|
|
/** Return 1 if <b>address</b> is already registered, else return 0. If address
|
|
|
|
* is already registered, and <b>update_expires</b> is non-zero, then update
|
|
|
|
* the expiry time on the mapping with update_expires if it is a
|
|
|
|
* mapping created by TrackHostExits. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2008-09-29 16:53:53 +02:00
|
|
|
addressmap_have_mapping(const char *address, int update_expiry)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2008-09-29 16:53:53 +02:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
if (!(ent=strmap_get_lc(addressmap, address)))
|
|
|
|
return 0;
|
|
|
|
if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
|
|
|
|
ent->expires=time(NULL) + update_expiry;
|
|
|
|
return 1;
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Register a request to map <b>address</b> to <b>new_address</b>,
|
2005-03-23 09:40:11 +01:00
|
|
|
* which will expire on <b>expires</b> (or 0 if never expires from
|
|
|
|
* config file, 1 if never expires from controller, 2 if never expires
|
|
|
|
* (virtual address mapping) from the controller.)
|
2005-02-22 01:53:08 +01:00
|
|
|
*
|
2005-02-23 07:40:48 +01:00
|
|
|
* <b>new_address</b> should be a newly dup'ed string, which we'll use or
|
2005-02-22 01:53:08 +01:00
|
|
|
* free as appropriate. We will leave address alone.
|
2005-02-23 07:40:48 +01:00
|
|
|
*
|
2011-09-08 17:54:24 +02:00
|
|
|
* If <b>wildcard_addr</b> is true, then the mapping will match any address
|
|
|
|
* equal to <b>address</b>, or any address ending with a period followed by
|
|
|
|
* <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
|
|
|
|
* both true, the mapping will rewrite addresses that end with
|
|
|
|
* ".<b>address</b>" into ones that end with ".<b>new_address</b>."
|
|
|
|
*
|
2011-11-26 02:13:55 +01:00
|
|
|
* If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
|
|
|
|
* <b>address</b> and <b>wildcard_addr</b> is equal to
|
|
|
|
* <b>wildcard_new_addr</b>, remove any mappings that exist from
|
|
|
|
* <b>address</b>.
|
|
|
|
*
|
|
|
|
*
|
2011-09-08 17:54:24 +02:00
|
|
|
* It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
|
|
|
|
* not set. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2008-02-21 19:45:11 +01:00
|
|
|
addressmap_register(const char *address, char *new_address, time_t expires,
|
2011-09-08 17:54:24 +02:00
|
|
|
addressmap_entry_source_t source,
|
|
|
|
const int wildcard_addr,
|
|
|
|
const int wildcard_new_addr)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2005-02-22 01:53:08 +01:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
|
2011-09-08 17:54:24 +02:00
|
|
|
if (wildcard_new_addr)
|
|
|
|
tor_assert(wildcard_addr);
|
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
ent = strmap_get(addressmap, address);
|
2011-11-26 02:13:55 +01:00
|
|
|
if (!new_address || (!strcasecmp(address,new_address) &&
|
|
|
|
wildcard_addr == wildcard_new_addr)) {
|
2005-03-02 22:02:11 +01:00
|
|
|
/* Remove the mapping, if any. */
|
2005-02-23 07:40:48 +01:00
|
|
|
tor_free(new_address);
|
|
|
|
if (ent) {
|
2005-03-02 22:02:11 +01:00
|
|
|
addressmap_ent_remove(address,ent);
|
2005-02-23 07:40:48 +01:00
|
|
|
strmap_remove(addressmap, address);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2005-03-23 06:32:06 +01:00
|
|
|
if (!ent) { /* make a new one and register it */
|
|
|
|
ent = tor_malloc_zero(sizeof(addressmap_entry_t));
|
|
|
|
strmap_set(addressmap, address, ent);
|
|
|
|
} else if (ent->new_address) { /* we need to clean up the old mapping. */
|
|
|
|
if (expires > 1) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
|
|
|
|
"since it's already mapped to '%s'",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(address),
|
|
|
|
safe_str_client(new_address),
|
|
|
|
safe_str_client(ent->new_address));
|
2005-03-23 06:32:06 +01:00
|
|
|
tor_free(new_address);
|
|
|
|
return;
|
|
|
|
}
|
2005-03-23 09:40:11 +01:00
|
|
|
if (address_is_in_virtual_range(ent->new_address) &&
|
|
|
|
expires != 2) {
|
|
|
|
/* XXX This isn't the perfect test; we want to avoid removing
|
|
|
|
* mappings set from the control interface _as virtual mapping */
|
2005-03-02 23:01:10 +01:00
|
|
|
addressmap_virtaddress_remove(address, ent);
|
2005-03-02 22:02:11 +01:00
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_free(ent->new_address);
|
2005-03-23 06:32:06 +01:00
|
|
|
} /* else { we have an in-progress resolve with no mapping. } */
|
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
ent->new_address = new_address;
|
2005-03-23 09:40:11 +01:00
|
|
|
ent->expires = expires==2 ? 1 : expires;
|
2005-02-22 01:53:08 +01:00
|
|
|
ent->num_resolve_failures = 0;
|
2008-02-21 19:45:11 +01:00
|
|
|
ent->source = source;
|
2011-09-08 17:54:24 +02:00
|
|
|
ent->src_wildcard = wildcard_addr ? 1 : 0;
|
|
|
|
ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(address),
|
|
|
|
safe_str_client(ent->new_address));
|
2007-07-10 19:14:51 +02:00
|
|
|
control_event_address_mapped(address, ent->new_address, expires, NULL);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** An attempt to resolve <b>address</b> failed at some OR.
|
|
|
|
* Increment the number of resolve failures we have on record
|
|
|
|
* for it, and then return that number.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
client_dns_incr_failures(const char *address)
|
2005-02-22 01:53:08 +01:00
|
|
|
{
|
2005-08-15 05:35:15 +02:00
|
|
|
addressmap_entry_t *ent = strmap_get(addressmap, address);
|
2005-02-22 01:53:08 +01:00
|
|
|
if (!ent) {
|
|
|
|
ent = tor_malloc_zero(sizeof(addressmap_entry_t));
|
2006-06-03 23:41:14 +02:00
|
|
|
ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
|
2005-02-22 01:53:08 +01:00
|
|
|
strmap_set(addressmap,address,ent);
|
|
|
|
}
|
2008-02-21 22:56:04 +01:00
|
|
|
if (ent->num_resolve_failures < SHORT_MAX)
|
|
|
|
++ent->num_resolve_failures; /* don't overflow */
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP, "Address %s now has %d resolve failures.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(address),
|
2009-09-28 15:08:32 +02:00
|
|
|
ent->num_resolve_failures);
|
2005-02-22 01:53:08 +01:00
|
|
|
return ent->num_resolve_failures;
|
|
|
|
}
|
|
|
|
|
2009-05-27 23:55:51 +02:00
|
|
|
/** If <b>address</b> is in the client DNS addressmap, reset
|
2005-08-15 05:35:15 +02:00
|
|
|
* the number of resolve failures we have on record for it.
|
|
|
|
* This is used when we fail a stream because it won't resolve:
|
|
|
|
* otherwise future attempts on that address will only try once.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
client_dns_clear_failures(const char *address)
|
|
|
|
{
|
|
|
|
addressmap_entry_t *ent = strmap_get(addressmap, address);
|
|
|
|
if (ent)
|
|
|
|
ent->num_resolve_failures = 0;
|
|
|
|
}
|
|
|
|
|
2006-12-26 23:41:43 +01:00
|
|
|
/** Record the fact that <b>address</b> resolved to <b>name</b>.
|
2005-02-22 01:53:08 +01:00
|
|
|
* We can now use this in subsequent streams via addressmap_rewrite()
|
|
|
|
* so we can more correctly choose an exit that will allow <b>address</b>.
|
2005-02-24 12:44:08 +01:00
|
|
|
*
|
|
|
|
* If <b>exitname</b> is defined, then append the addresses with
|
|
|
|
* ".exitname.exit" before registering the mapping.
|
2005-09-02 20:53:31 +02:00
|
|
|
*
|
|
|
|
* If <b>ttl</b> is nonnegative, the mapping will be valid for
|
2006-06-03 23:47:26 +02:00
|
|
|
* <b>ttl</b>seconds; otherwise, we use the default.
|
2005-02-22 01:53:08 +01:00
|
|
|
*/
|
2006-12-26 23:41:43 +01:00
|
|
|
static void
|
|
|
|
client_dns_set_addressmap_impl(const char *address, const char *name,
|
|
|
|
const char *exitname,
|
|
|
|
int ttl)
|
2005-02-22 01:53:08 +01:00
|
|
|
{
|
2006-03-17 05:43:37 +01:00
|
|
|
/* <address>.<hex or nickname>.exit\0 or just <address>\0 */
|
2006-10-03 20:58:47 +02:00
|
|
|
char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
|
2006-12-20 10:25:58 +01:00
|
|
|
/* 123.123.123.123.<hex or nickname>.exit\0 or just 123.123.123.123\0 */
|
2006-10-03 20:58:47 +02:00
|
|
|
char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2006-06-03 23:41:14 +02:00
|
|
|
tor_assert(address);
|
2006-12-26 23:41:43 +01:00
|
|
|
tor_assert(name);
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2006-06-03 23:47:26 +02:00
|
|
|
if (ttl<0)
|
|
|
|
ttl = DEFAULT_DNS_TTL;
|
|
|
|
else
|
|
|
|
ttl = dns_clip_ttl(ttl);
|
2005-09-02 20:53:31 +02:00
|
|
|
|
2005-02-24 12:44:08 +01:00
|
|
|
if (exitname) {
|
2006-10-03 20:58:47 +02:00
|
|
|
/* XXXX fails to ever get attempts to get an exit address of
|
|
|
|
* google.com.digest[=~]nickname.exit; we need a syntax for this that
|
|
|
|
* won't make strict RFC952-compliant applications (like us) barf. */
|
2005-02-24 12:44:08 +01:00
|
|
|
tor_snprintf(extendedaddress, sizeof(extendedaddress),
|
|
|
|
"%s.%s.exit", address, exitname);
|
|
|
|
tor_snprintf(extendedval, sizeof(extendedval),
|
2006-12-26 23:41:43 +01:00
|
|
|
"%s.%s.exit", name, exitname);
|
2005-02-24 12:44:08 +01:00
|
|
|
} else {
|
|
|
|
tor_snprintf(extendedaddress, sizeof(extendedaddress),
|
|
|
|
"%s", address);
|
|
|
|
tor_snprintf(extendedval, sizeof(extendedval),
|
2006-12-26 23:41:43 +01:00
|
|
|
"%s", name);
|
2005-02-24 12:44:08 +01:00
|
|
|
}
|
2005-12-14 21:40:40 +01:00
|
|
|
addressmap_register(extendedaddress, tor_strdup(extendedval),
|
2011-09-08 17:54:24 +02:00
|
|
|
time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
|
2005-02-22 01:53:08 +01:00
|
|
|
}
|
|
|
|
|
2006-12-26 23:41:43 +01:00
|
|
|
/** Record the fact that <b>address</b> resolved to <b>val</b>.
|
|
|
|
* We can now use this in subsequent streams via addressmap_rewrite()
|
|
|
|
* so we can more correctly choose an exit that will allow <b>address</b>.
|
|
|
|
*
|
|
|
|
* If <b>exitname</b> is defined, then append the addresses with
|
|
|
|
* ".exitname.exit" before registering the mapping.
|
|
|
|
*
|
|
|
|
* If <b>ttl</b> is nonnegative, the mapping will be valid for
|
|
|
|
* <b>ttl</b>seconds; otherwise, we use the default.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
client_dns_set_addressmap(const char *address, uint32_t val,
|
|
|
|
const char *exitname,
|
|
|
|
int ttl)
|
|
|
|
{
|
|
|
|
struct in_addr in;
|
|
|
|
char valbuf[INET_NTOA_BUF_LEN];
|
|
|
|
|
|
|
|
tor_assert(address);
|
|
|
|
|
|
|
|
if (tor_inet_aton(address, &in))
|
|
|
|
return; /* If address was an IP address already, don't add a mapping. */
|
|
|
|
in.s_addr = htonl(val);
|
|
|
|
tor_inet_ntoa(&in,valbuf,sizeof(valbuf));
|
|
|
|
|
|
|
|
client_dns_set_addressmap_impl(address, valbuf, exitname, ttl);
|
|
|
|
}
|
|
|
|
|
2007-02-02 19:58:11 +01:00
|
|
|
/** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
|
|
|
|
* resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
|
|
|
|
*
|
|
|
|
* If <b>exitname</b> is defined, then append the addresses with
|
|
|
|
* ".exitname.exit" before registering the mapping.
|
|
|
|
*
|
|
|
|
* If <b>ttl</b> is nonnegative, the mapping will be valid for
|
|
|
|
* <b>ttl</b>seconds; otherwise, we use the default.
|
|
|
|
*/
|
2006-12-26 23:41:43 +01:00
|
|
|
static void
|
|
|
|
client_dns_set_reverse_addressmap(const char *address, const char *v,
|
|
|
|
const char *exitname,
|
|
|
|
int ttl)
|
|
|
|
{
|
2012-01-11 20:02:59 +01:00
|
|
|
char *s = NULL;
|
|
|
|
tor_asprintf(&s, "REVERSE[%s]", address);
|
2006-12-26 23:41:43 +01:00
|
|
|
client_dns_set_addressmap_impl(s, v, exitname, ttl);
|
|
|
|
tor_free(s);
|
|
|
|
}
|
|
|
|
|
2006-04-18 05:36:28 +02:00
|
|
|
/* By default, we hand out 127.192.0.1 through 127.254.254.254.
|
2005-03-02 20:26:46 +01:00
|
|
|
* These addresses should map to localhost, so even if the
|
|
|
|
* application accidentally tried to connect to them directly (not
|
|
|
|
* via Tor), it wouldn't get too far astray.
|
|
|
|
*
|
2007-02-02 21:06:43 +01:00
|
|
|
* These options are configured by parse_virtual_addr_network().
|
2005-03-02 20:26:46 +01:00
|
|
|
*/
|
2008-02-16 00:39:04 +01:00
|
|
|
/** Which network should we use for virtual IPv4 addresses? Only the first
|
|
|
|
* bits of this value are fixed. */
|
2006-04-18 05:36:28 +02:00
|
|
|
static uint32_t virtual_addr_network = 0x7fc00000u;
|
2008-02-16 00:39:04 +01:00
|
|
|
/** How many bits of <b>virtual_addr_network</b> are fixed? */
|
2007-07-19 21:40:45 +02:00
|
|
|
static maskbits_t virtual_addr_netmask_bits = 10;
|
2008-02-16 00:39:04 +01:00
|
|
|
/** What's the next virtual address we will hand out? */
|
2006-04-18 05:36:28 +02:00
|
|
|
static uint32_t next_virtual_addr = 0x7fc00000u;
|
|
|
|
|
|
|
|
/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
|
|
|
|
* it's a valid set of virtual addresses to hand out in response to MAPADDRESS
|
2006-04-18 05:51:18 +02:00
|
|
|
* requests. Return 0 on success; set *msg (if provided) to a newly allocated
|
|
|
|
* string and return -1 on failure. If validate_only is false, sets the
|
|
|
|
* actual virtual address range to the parsed value. */
|
2006-04-18 05:36:28 +02:00
|
|
|
int
|
|
|
|
parse_virtual_addr_network(const char *val, int validate_only,
|
2006-04-18 05:51:18 +02:00
|
|
|
char **msg)
|
2006-04-18 05:36:28 +02:00
|
|
|
{
|
2007-07-19 21:40:45 +02:00
|
|
|
uint32_t addr;
|
2006-04-18 05:36:28 +02:00
|
|
|
uint16_t port_min, port_max;
|
2007-07-19 21:40:45 +02:00
|
|
|
maskbits_t bits;
|
2006-04-18 05:36:28 +02:00
|
|
|
|
2007-07-19 21:40:45 +02:00
|
|
|
if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
|
2006-04-18 05:51:18 +02:00
|
|
|
if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
|
2006-04-18 05:36:28 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port_min != 1 || port_max != 65535) {
|
2006-04-18 05:51:18 +02:00
|
|
|
if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
|
2006-04-18 05:36:28 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bits > 16) {
|
2006-04-18 07:03:09 +02:00
|
|
|
if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
|
2006-04-18 05:51:18 +02:00
|
|
|
"network or larger");
|
2006-04-18 05:36:28 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (validate_only)
|
|
|
|
return 0;
|
|
|
|
|
2008-02-22 20:09:45 +01:00
|
|
|
virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
|
2006-04-18 05:36:28 +02:00
|
|
|
virtual_addr_netmask_bits = bits;
|
|
|
|
|
2007-07-19 21:40:45 +02:00
|
|
|
if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
|
2006-04-18 05:36:28 +02:00
|
|
|
next_virtual_addr = addr;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-03-02 20:26:46 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true iff <b>addr</b> is likely to have been returned by
|
2005-03-02 22:02:11 +01:00
|
|
|
* client_dns_get_unused_address.
|
2005-03-02 20:26:46 +01:00
|
|
|
**/
|
2007-10-02 22:35:23 +02:00
|
|
|
static int
|
2005-10-05 04:06:36 +02:00
|
|
|
address_is_in_virtual_range(const char *address)
|
2005-03-02 20:26:46 +01:00
|
|
|
{
|
|
|
|
struct in_addr in;
|
2005-10-05 04:06:36 +02:00
|
|
|
tor_assert(address);
|
|
|
|
if (!strcasecmpend(address, ".virtual")) {
|
2005-03-02 20:26:46 +01:00
|
|
|
return 1;
|
2005-10-05 04:06:36 +02:00
|
|
|
} else if (tor_inet_aton(address, &in)) {
|
|
|
|
uint32_t addr = ntohl(in.s_addr);
|
2007-07-19 21:40:45 +02:00
|
|
|
if (!addr_mask_cmp_bits(addr, virtual_addr_network,
|
|
|
|
virtual_addr_netmask_bits))
|
2005-03-02 20:26:46 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-01-07 18:18:37 +01:00
|
|
|
/** Increment the value of next_virtual_addr; reset it to the start of the
|
|
|
|
* virtual address range if it wraps around.
|
|
|
|
*/
|
|
|
|
static INLINE void
|
|
|
|
increment_virtual_addr(void)
|
|
|
|
{
|
|
|
|
++next_virtual_addr;
|
|
|
|
if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
|
|
|
|
virtual_addr_netmask_bits))
|
|
|
|
next_virtual_addr = virtual_addr_network;
|
|
|
|
}
|
|
|
|
|
2005-03-02 20:26:46 +01:00
|
|
|
/** Return a newly allocated string holding an address of <b>type</b>
|
|
|
|
* (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
|
|
|
|
* and that is very unlikely to be the address of any real host.
|
2011-01-05 22:36:48 +01:00
|
|
|
*
|
|
|
|
* May return NULL if we have run out of virtual addresses.
|
2005-03-02 20:26:46 +01:00
|
|
|
*/
|
2005-03-02 22:02:11 +01:00
|
|
|
static char *
|
|
|
|
addressmap_get_virtual_address(int type)
|
2005-03-02 20:26:46 +01:00
|
|
|
{
|
|
|
|
char buf[64];
|
2007-08-15 23:53:34 +02:00
|
|
|
tor_assert(addressmap);
|
2005-03-02 20:26:46 +01:00
|
|
|
|
|
|
|
if (type == RESOLVED_TYPE_HOSTNAME) {
|
2005-03-23 09:40:11 +01:00
|
|
|
char rand[10];
|
2005-03-02 20:26:46 +01:00
|
|
|
do {
|
|
|
|
crypto_rand(rand, sizeof(rand));
|
|
|
|
base32_encode(buf,sizeof(buf),rand,sizeof(rand));
|
|
|
|
strlcat(buf, ".virtual", sizeof(buf));
|
|
|
|
} while (strmap_get(addressmap, buf));
|
|
|
|
return tor_strdup(buf);
|
|
|
|
} else if (type == RESOLVED_TYPE_IPV4) {
|
2006-04-18 05:51:18 +02:00
|
|
|
// This is an imperfect estimate of how many addresses are available, but
|
|
|
|
// that's ok.
|
2011-01-06 19:40:27 +01:00
|
|
|
struct in_addr in;
|
2006-04-18 05:51:18 +02:00
|
|
|
uint32_t available = 1u << (32-virtual_addr_netmask_bits);
|
2006-04-18 05:36:28 +02:00
|
|
|
while (available) {
|
2005-03-02 20:26:46 +01:00
|
|
|
/* Don't hand out any .0 or .255 address. */
|
2006-04-18 05:36:28 +02:00
|
|
|
while ((next_virtual_addr & 0xff) == 0 ||
|
|
|
|
(next_virtual_addr & 0xff) == 0xff) {
|
2011-01-07 18:18:37 +01:00
|
|
|
increment_virtual_addr();
|
2011-01-06 19:29:36 +01:00
|
|
|
if (! --available) {
|
|
|
|
log_warn(LD_CONFIG, "Ran out of virtual addresses!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-04-18 05:36:28 +02:00
|
|
|
}
|
2011-01-06 19:40:27 +01:00
|
|
|
in.s_addr = htonl(next_virtual_addr);
|
|
|
|
tor_inet_ntoa(&in, buf, sizeof(buf));
|
|
|
|
if (!strmap_get(addressmap, buf)) {
|
2011-01-07 18:18:37 +01:00
|
|
|
increment_virtual_addr();
|
2005-03-02 20:26:46 +01:00
|
|
|
break;
|
2007-08-15 23:53:34 +02:00
|
|
|
}
|
2005-03-02 20:26:46 +01:00
|
|
|
|
2011-01-07 18:18:37 +01:00
|
|
|
increment_virtual_addr();
|
2006-04-18 05:36:28 +02:00
|
|
|
--available;
|
2011-01-08 04:03:22 +01:00
|
|
|
// log_info(LD_CONFIG, "%d addrs available", (int)available);
|
2011-01-05 22:02:43 +01:00
|
|
|
if (! available) {
|
2006-04-18 05:36:28 +02:00
|
|
|
log_warn(LD_CONFIG, "Ran out of virtual addresses!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-03-02 20:26:46 +01:00
|
|
|
}
|
|
|
|
return tor_strdup(buf);
|
|
|
|
} else {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
|
2005-03-02 20:26:46 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-17 13:38:37 +01:00
|
|
|
/** A controller has requested that we map some address of type
|
|
|
|
* <b>type</b> to the address <b>new_address</b>. Choose an address
|
|
|
|
* that is unlikely to be used, and map it, and return it in a newly
|
|
|
|
* allocated string. If another address of the same type is already
|
|
|
|
* mapped to <b>new_address</b>, try to return a copy of that address.
|
|
|
|
*
|
2011-01-05 22:36:48 +01:00
|
|
|
* The string in <b>new_address</b> may be freed or inserted into a map
|
|
|
|
* as appropriate. May return NULL if are out of virtual addresses.
|
2005-03-17 13:38:37 +01:00
|
|
|
**/
|
2005-03-23 09:40:11 +01:00
|
|
|
const char *
|
2005-03-02 22:02:11 +01:00
|
|
|
addressmap_register_virtual_address(int type, char *new_address)
|
|
|
|
{
|
2005-03-02 23:01:10 +01:00
|
|
|
char **addrp;
|
|
|
|
virtaddress_entry_t *vent;
|
2011-01-05 22:36:48 +01:00
|
|
|
int vent_needs_to_be_added = 0;
|
2005-03-02 23:01:10 +01:00
|
|
|
|
2005-03-02 22:02:11 +01:00
|
|
|
tor_assert(new_address);
|
2005-03-23 09:40:11 +01:00
|
|
|
tor_assert(addressmap);
|
|
|
|
tor_assert(virtaddress_reversemap);
|
2005-03-02 22:02:11 +01:00
|
|
|
|
2005-03-02 23:01:10 +01:00
|
|
|
vent = strmap_get(virtaddress_reversemap, new_address);
|
2005-03-23 09:40:11 +01:00
|
|
|
if (!vent) {
|
2005-03-02 23:01:10 +01:00
|
|
|
vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
|
2011-01-05 22:36:48 +01:00
|
|
|
vent_needs_to_be_added = 1;
|
2005-03-23 09:40:11 +01:00
|
|
|
}
|
2005-03-02 23:01:10 +01:00
|
|
|
|
|
|
|
addrp = (type == RESOLVED_TYPE_IPV4) ?
|
|
|
|
&vent->ipv4_address : &vent->hostname_address;
|
|
|
|
if (*addrp) {
|
|
|
|
addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
|
2005-12-14 21:40:40 +01:00
|
|
|
if (ent && ent->new_address &&
|
|
|
|
!strcasecmp(new_address, ent->new_address)) {
|
2005-03-23 09:40:11 +01:00
|
|
|
tor_free(new_address);
|
2011-01-05 22:36:48 +01:00
|
|
|
tor_assert(!vent_needs_to_be_added);
|
2005-03-02 23:01:10 +01:00
|
|
|
return tor_strdup(*addrp);
|
2005-03-23 09:40:11 +01:00
|
|
|
} else
|
2006-02-13 10:02:35 +01:00
|
|
|
log_warn(LD_BUG,
|
|
|
|
"Internal confusion: I thought that '%s' was mapped to by "
|
|
|
|
"'%s', but '%s' really maps to '%s'. This is a harmless bug.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(new_address),
|
|
|
|
safe_str_client(*addrp),
|
|
|
|
safe_str_client(*addrp),
|
|
|
|
ent?safe_str_client(ent->new_address):"(nothing)");
|
2005-03-02 22:02:11 +01:00
|
|
|
}
|
|
|
|
|
2005-03-02 23:01:10 +01:00
|
|
|
tor_free(*addrp);
|
|
|
|
*addrp = addressmap_get_virtual_address(type);
|
2011-01-05 22:36:48 +01:00
|
|
|
if (!*addrp) {
|
|
|
|
tor_free(vent);
|
|
|
|
tor_free(new_address);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-25 16:48:16 +02:00
|
|
|
log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
|
2011-01-05 22:36:48 +01:00
|
|
|
if (vent_needs_to_be_added)
|
|
|
|
strmap_set(virtaddress_reversemap, new_address, vent);
|
2011-09-08 17:54:24 +02:00
|
|
|
addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
|
2005-03-23 09:40:11 +01:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
{
|
2005-06-15 20:34:46 +02:00
|
|
|
/* Try to catch possible bugs */
|
2005-03-23 09:40:11 +01:00
|
|
|
addressmap_entry_t *ent;
|
|
|
|
ent = strmap_get(addressmap, *addrp);
|
|
|
|
tor_assert(ent);
|
|
|
|
tor_assert(!strcasecmp(ent->new_address,new_address));
|
|
|
|
vent = strmap_get(virtaddress_reversemap, new_address);
|
|
|
|
tor_assert(vent);
|
|
|
|
tor_assert(!strcasecmp(*addrp,
|
|
|
|
(type == RESOLVED_TYPE_IPV4) ?
|
|
|
|
vent->ipv4_address : vent->hostname_address));
|
2007-05-25 16:48:16 +02:00
|
|
|
log_info(LD_APP, "Map from %s to %s okay.",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(*addrp),
|
|
|
|
safe_str_client(new_address));
|
2005-03-23 09:40:11 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-03-02 23:01:10 +01:00
|
|
|
return *addrp;
|
2005-03-02 22:02:11 +01:00
|
|
|
}
|
|
|
|
|
2007-01-11 17:02:39 +01:00
|
|
|
/** Return 1 if <b>address</b> has funny characters in it like colons. Return
|
|
|
|
* 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
|
|
|
|
* should be true if we're using this address as a client; false if we're
|
|
|
|
* using it as a server.
|
2005-02-01 13:19:44 +01:00
|
|
|
*/
|
2006-12-29 06:51:50 +01:00
|
|
|
int
|
2007-01-11 17:02:39 +01:00
|
|
|
address_is_invalid_destination(const char *address, int client)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2007-01-11 17:02:39 +01:00
|
|
|
if (client) {
|
|
|
|
if (get_options()->AllowNonRFC953Hostnames)
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if (get_options()->ServerDNSAllowNonRFC953Hostnames)
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-19 20:48:58 +01:00
|
|
|
|
|
|
|
while (*address) {
|
|
|
|
if (TOR_ISALNUM(*address) ||
|
|
|
|
*address == '-' ||
|
|
|
|
*address == '.' ||
|
|
|
|
*address == '_') /* Underscore is not allowed, but Windows does it
|
|
|
|
* sometimes, just to thumb its nose at the IETF. */
|
|
|
|
++address;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
2005-02-01 13:19:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-09 23:11:50 +02:00
|
|
|
/** Iterate over all address mappings which have expiry times between
|
2005-03-11 22:39:39 +01:00
|
|
|
* min_expires and max_expires, inclusive. If sl is provided, add an
|
2007-07-16 18:58:11 +02:00
|
|
|
* "old-addr new-addr expiry" string to sl for each mapping, omitting
|
|
|
|
* the expiry time if want_expiry is false. If sl is NULL, remove the
|
|
|
|
* mappings.
|
2005-03-11 22:39:39 +01:00
|
|
|
*/
|
2005-03-03 07:37:54 +01:00
|
|
|
void
|
2005-12-14 21:40:40 +01:00
|
|
|
addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
|
2007-07-16 18:58:11 +02:00
|
|
|
time_t max_expires, int want_expiry)
|
2005-03-03 07:37:54 +01:00
|
|
|
{
|
|
|
|
strmap_iter_t *iter;
|
|
|
|
const char *key;
|
|
|
|
void *_val;
|
|
|
|
addressmap_entry_t *val;
|
|
|
|
|
2005-08-22 02:34:42 +02:00
|
|
|
if (!addressmap)
|
|
|
|
addressmap_init();
|
|
|
|
|
2005-03-11 22:42:32 +01:00
|
|
|
for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
|
2005-03-03 07:37:54 +01:00
|
|
|
strmap_iter_get(iter, &key, &_val);
|
|
|
|
val = _val;
|
|
|
|
if (val->expires >= min_expires && val->expires <= max_expires) {
|
2005-03-11 22:42:32 +01:00
|
|
|
if (!sl) {
|
|
|
|
iter = strmap_iter_next_rmv(addressmap,iter);
|
2005-11-23 05:18:45 +01:00
|
|
|
addressmap_ent_remove(key, val);
|
2005-03-11 22:42:32 +01:00
|
|
|
continue;
|
2005-03-28 04:03:51 +02:00
|
|
|
} else if (val->new_address) {
|
2012-06-28 05:55:01 +02:00
|
|
|
const char *src_wc = val->src_wildcard ? "*." : "";
|
|
|
|
const char *dst_wc = val->dst_wildcard ? "*." : "";
|
2007-07-16 18:58:11 +02:00
|
|
|
if (want_expiry) {
|
|
|
|
if (val->expires < 3 || val->expires == TIME_MAX)
|
2012-06-28 05:55:01 +02:00
|
|
|
smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
|
|
|
|
src_wc, key, dst_wc, val->new_address);
|
2007-07-16 18:58:11 +02:00
|
|
|
else {
|
|
|
|
char time[ISO_TIME_LEN+1];
|
2007-07-26 00:56:54 +02:00
|
|
|
format_iso_time(time, val->expires);
|
2012-06-28 05:55:01 +02:00
|
|
|
smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
|
|
|
|
src_wc, key, dst_wc, val->new_address,
|
|
|
|
time);
|
2007-07-16 18:58:11 +02:00
|
|
|
}
|
|
|
|
} else {
|
2012-06-28 05:55:01 +02:00
|
|
|
smartlist_add_asprintf(sl, "%s%s %s%s",
|
|
|
|
src_wc, key, dst_wc, val->new_address);
|
2007-07-16 18:58:11 +02:00
|
|
|
}
|
2005-03-11 22:39:39 +01:00
|
|
|
}
|
2005-03-03 07:37:54 +01:00
|
|
|
}
|
2005-03-11 22:42:32 +01:00
|
|
|
iter = strmap_iter_next(addressmap,iter);
|
2005-03-03 07:37:54 +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();
|
2008-01-20 06:54:15 +01:00
|
|
|
int reject = smartlist_string_num_isin(options->RejectPlaintextPorts, port);
|
|
|
|
|
|
|
|
if (smartlist_string_num_isin(options->WarnPlaintextPorts, port)) {
|
|
|
|
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) {
|
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);
|
|
|
|
}
|
|
|
|
|
2007-02-02 21:06:43 +01:00
|
|
|
/** Connection <b>conn</b> just finished its socks handshake, or the
|
2006-03-12 06:04:16 +01:00
|
|
|
* 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.
|
2004-05-10 06:42:22 +02:00
|
|
|
*
|
2006-02-03 12:37:19 +01:00
|
|
|
* First, parse whether it's a .exit address, remap it, and so on. Then
|
2006-12-10 09:04:50 +01:00
|
|
|
* if it's for a general circuit, try to attach it to a circuit (or launch
|
2006-02-03 12:37:19 +01:00
|
|
|
* 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).
|
2007-04-30 16:09:11 +02:00
|
|
|
*
|
|
|
|
* The stream will exit from the hop
|
2007-05-01 01:24:38 +02:00
|
|
|
* indicated by <b>cpath</b>, or from the last hop in circ's cpath if
|
2007-04-30 16:09:11 +02:00
|
|
|
* <b>cpath</b> is NULL.
|
2004-05-10 06:42:22 +02:00
|
|
|
*/
|
2006-02-03 12:37:19 +01:00
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
|
2007-04-30 13:10:45 +02:00
|
|
|
origin_circuit_t *circ,
|
|
|
|
crypt_path_t *cpath)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2006-02-03 12:37:19 +01:00
|
|
|
socks_request_t *socks = conn->socks_request;
|
2004-11-30 04:44:10 +01:00
|
|
|
hostname_type_t addresstype;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2007-05-25 16:48:16 +02:00
|
|
|
struct in_addr addr_tmp;
|
2011-04-03 23:08:59 +02:00
|
|
|
/* We set this to true if this is an address we should automatically
|
|
|
|
* remap to a local address in VirtualAddrNetwork */
|
2007-05-25 16:48:16 +02:00
|
|
|
int automap = 0;
|
2007-05-25 20:22:43 +02:00
|
|
|
char orig_address[MAX_SOCKS_ADDR_LEN];
|
2007-07-10 19:14:51 +02:00
|
|
|
time_t map_expires = TIME_MAX;
|
2008-02-19 22:30:24 +01:00
|
|
|
time_t now = time(NULL);
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_t *base_conn = ENTRY_TO_CONN(conn);
|
2012-05-11 23:00:41 +02:00
|
|
|
addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_strlower(socks->address); /* normalize it */
|
2007-05-25 20:22:43 +02:00
|
|
|
strlcpy(orig_address, socks->address, sizeof(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
|
|
|
|
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));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-07-08 21:15:59 +02:00
|
|
|
if (! conn->original_dest_address)
|
|
|
|
conn->original_dest_address = tor_strdup(conn->socks_request->address);
|
|
|
|
|
2007-05-25 16:48:16 +02:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE &&
|
|
|
|
!tor_inet_aton(socks->address, &addr_tmp) &&
|
|
|
|
options->AutomapHostsOnResolve && options->AutomapHostsSuffixes) {
|
|
|
|
SMARTLIST_FOREACH(options->AutomapHostsSuffixes, const char *, cp,
|
|
|
|
if (!strcasecmpend(socks->address, cp)) {
|
|
|
|
automap = 1;
|
|
|
|
break;
|
|
|
|
});
|
|
|
|
if (automap) {
|
|
|
|
const char *new_addr;
|
|
|
|
new_addr = addressmap_register_virtual_address(
|
|
|
|
RESOLVED_TYPE_IPV4, 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));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
|
|
|
|
return -1;
|
|
|
|
}
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-26 23:41:43 +01:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
|
2007-07-10 19:14:51 +02:00
|
|
|
if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
|
|
|
|
&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]",
|
|
|
|
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,
|
2007-07-10 19:14:51 +02:00
|
|
|
map_expires);
|
2006-12-26 23:41:43 +01:00
|
|
|
connection_mark_unattached_ap(conn,
|
2008-04-22 19:21:12 +02:00
|
|
|
END_STREAM_REASON_DONE |
|
2008-09-26 22:25:35 +02:00
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
|
2006-12-26 23:41:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2007-08-27 17:33:58 +02:00
|
|
|
if (options->ClientDNSRejectInternalAddresses) {
|
|
|
|
/* Don't let people try to do a reverse lookup on 10.0.0.1. */
|
|
|
|
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);
|
|
|
|
connection_mark_unattached_ap(conn,
|
|
|
|
END_STREAM_REASON_SOCKSPROTOCOL |
|
|
|
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2007-05-25 16:48:16 +02:00
|
|
|
} else if (!automap) {
|
|
|
|
/* For address map controls, remap the address. */
|
2007-07-10 19:14:51 +02:00
|
|
|
if (addressmap_rewrite(socks->address, sizeof(socks->address),
|
2012-05-11 23:00:41 +02:00
|
|
|
&map_expires, &exit_source)) {
|
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
|
|
|
}
|
2006-12-26 23:41:43 +01:00
|
|
|
}
|
2005-02-22 01:53:08 +01:00
|
|
|
|
2007-05-25 16:48:16 +02:00
|
|
|
if (!automap && address_is_in_virtual_range(socks->address)) {
|
2005-03-02 20:26:46 +01:00
|
|
|
/* This address was probably handed out by client_dns_get_unmapped_address,
|
|
|
|
* but the mapping was discarded for some reason. We *don't* want to send
|
2006-02-03 12:37:19 +01:00
|
|
|
* the address through Tor; that's likely to fail, and may leak
|
2005-03-02 20:26:46 +01:00
|
|
|
* information.
|
|
|
|
*/
|
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));
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
|
2005-03-02 20:26:46 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-11-29 09:34:54 +01:00
|
|
|
/* Parse the address provided by SOCKS. Modify it in-place if it
|
|
|
|
* specifies a hidden-service (.onion) or particular exit node (.exit).
|
|
|
|
*/
|
2012-05-11 23:00:41 +02:00
|
|
|
addresstype = parse_extended_hostname(socks->address);
|
2004-11-29 09:34:54 +01:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-11-30 04:44:10 +01:00
|
|
|
if (addresstype == EXIT_HOSTNAME) {
|
2005-05-11 00:12:48 +02:00
|
|
|
/* foo.exit -- modify conn->chosen_exit_node to specify the exit
|
2009-08-08 01:26:41 +02:00
|
|
|
* node, and conn->address to hold only the address portion. */
|
2004-11-29 09:34:54 +01:00
|
|
|
char *s = strrchr(socks->address,'.');
|
2011-04-03 23:08:59 +02:00
|
|
|
|
|
|
|
/* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
|
|
|
|
routerset_t *excludeset = options->StrictNodes ?
|
|
|
|
options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
|
2011-04-27 20:36:30 +02:00
|
|
|
const node_t *node;
|
2011-04-03 23:08:59 +02:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
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') {
|
|
|
|
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 {
|
2011-04-03 23:08:59 +02:00
|
|
|
/* It looks like they just asked for "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
|
|
|
}
|
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;
|
|
|
|
}
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024-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
|
|
|
}
|
|
|
|
|
2004-11-30 04:44:10 +01:00
|
|
|
if (addresstype != ONION_HOSTNAME) {
|
2004-11-29 09:34:54 +01:00
|
|
|
/* not a hidden-service request (i.e. normal or .exit) */
|
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;
|
|
|
|
}
|
|
|
|
|
2011-05-31 16:05:40 +02:00
|
|
|
if (options->Tor2webMode) {
|
|
|
|
log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s "
|
|
|
|
"because tor2web mode is enabled.",
|
|
|
|
safe_str_client(socks->address));
|
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-09-22 02:44:07 +02:00
|
|
|
if (socks->command == SOCKS_COMMAND_RESOLVE) {
|
2005-02-22 01:53:08 +01:00
|
|
|
uint32_t answer;
|
2004-12-06 07:06:13 +01:00
|
|
|
struct in_addr in;
|
2004-12-05 13:47:46 +01:00
|
|
|
/* Reply to resolves immediately if we can. */
|
2005-02-22 01:53:08 +01:00
|
|
|
if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
|
2007-05-25 20:22:43 +02:00
|
|
|
/* leave it in network order */
|
|
|
|
answer = in.s_addr;
|
|
|
|
/* remember _what_ is supposed to have been resolved. */
|
|
|
|
strlcpy(socks->address, orig_address, sizeof(socks->address));
|
2004-12-05 13:47:46 +01:00
|
|
|
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
|
2010-12-14 01:34:01 +01:00
|
|
|
(uint8_t*)&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 */
|
2006-09-22 02:44:07 +02:00
|
|
|
} else if (socks->command == SOCKS_COMMAND_CONNECT) {
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
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;
|
|
|
|
}
|
2011-01-26 17:35:24 +01:00
|
|
|
if (options->ClientRejectInternalAddresses &&
|
|
|
|
!conn->use_begindir && !conn->chosen_exit_name && !circ) {
|
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;
|
|
|
|
}
|
|
|
|
}
|
2005-08-15 05:25:40 +02: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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-20 06:54:15 +01:00
|
|
|
/* warn or reject if it's using a dangerous port */
|
|
|
|
if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
|
|
|
|
if (consider_plaintext_ports(conn, socks->port) < 0)
|
|
|
|
return -1;
|
|
|
|
|
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 {
|
|
|
|
tor_fragile_assert();
|
2005-03-12 05:22:01 +01:00
|
|
|
}
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2007-04-30 13:10:45 +02:00
|
|
|
if ((circ && connection_ap_handshake_attach_chosen_circuit(
|
|
|
|
conn, circ, cpath) < 0) ||
|
2006-03-12 06:04:16 +01:00
|
|
|
(!circ &&
|
|
|
|
connection_ap_handshake_attach_circuit(conn) < 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
|
|
|
}
|
2005-08-15 05:25:40 +02:00
|
|
|
return 0;
|
2004-04-01 04:41:41 +02:00
|
|
|
} else {
|
|
|
|
/* it's a hidden-service request */
|
2004-04-08 00:41:00 +02:00
|
|
|
rend_cache_entry_t *entry;
|
2004-04-18 11:04:37 +02:00
|
|
|
int r;
|
2008-09-24 16:44:29 +02:00
|
|
|
rend_service_authorization_t *client_auth;
|
2011-07-20 18:55:42 +02:00
|
|
|
rend_data_t *rend_data;
|
2007-05-25 16:48:16 +02:00
|
|
|
tor_assert(!automap);
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
ENTRY_TO_EDGE_CONN(conn)->rend_data = rend_data =
|
|
|
|
tor_malloc_zero(sizeof(rend_data_t));
|
|
|
|
strlcpy(rend_data->onion_address, socks->address,
|
|
|
|
sizeof(rend_data->onion_address));
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_REND,"Got a hidden service request for ID '%s'",
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(rend_data->onion_address));
|
2004-04-01 04:41:41 +02:00
|
|
|
/* see if we already have it cached */
|
2011-07-20 18:55:42 +02:00
|
|
|
r = rend_cache_lookup_entry(rend_data->onion_address, -1, &entry);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (r<0) {
|
2007-03-04 21:11:46 +01:00
|
|
|
log_warn(LD_BUG,"Invalid service name '%s'",
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(rend_data->onion_address));
|
2005-04-03 00:11:24 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
2004-04-18 11:04:37 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2008-02-19 22:30:24 +01:00
|
|
|
|
|
|
|
/* Help predict this next time. We're not sure if it will need
|
|
|
|
* a stable circuit yet, but we know we'll need *something*. */
|
|
|
|
rep_hist_note_used_internal(now, 0, 1);
|
|
|
|
|
2008-09-24 16:44:29 +02:00
|
|
|
/* Look up if we have client authorization for it. */
|
|
|
|
client_auth = rend_client_lookup_service_authorization(
|
2011-07-20 18:55:42 +02:00
|
|
|
rend_data->onion_address);
|
2008-09-24 16:44:29 +02:00
|
|
|
if (client_auth) {
|
|
|
|
log_info(LD_REND, "Using previously configured client authorization "
|
|
|
|
"for hidden service request.");
|
2011-07-20 18:55:42 +02:00
|
|
|
memcpy(rend_data->descriptor_cookie,
|
2008-09-24 16:44:29 +02:00
|
|
|
client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN);
|
2011-07-20 18:55:42 +02:00
|
|
|
rend_data->auth_type = client_auth->auth_type;
|
2008-09-24 16:44:29 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (r==0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
|
2011-07-20 18:55:42 +02:00
|
|
|
safe_str_client(rend_data->onion_address));
|
|
|
|
rend_client_refetch_v2_renddesc(rend_data);
|
2005-12-07 00:43:52 +01:00
|
|
|
} else { /* r > 0 */
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
2009-06-12 11:39:35 +02:00
|
|
|
log_info(LD_REND, "Descriptor is here. Great.");
|
|
|
|
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
2011-07-20 18:55:42 +02:00
|
|
|
if (!base_conn->marked_for_close)
|
2009-06-12 11:39:35 +02:00
|
|
|
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
|
|
|
|
return -1;
|
2004-04-18 11:04:37 +02:00
|
|
|
}
|
|
|
|
}
|
2005-12-07 00:43:52 +01:00
|
|
|
return 0;
|
2004-04-01 04:41:41 +02: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;
|
|
|
|
|
|
|
|
#ifdef OPENBSD
|
|
|
|
/* 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
|
|
|
|
|
2006-08-10 11:01:37 +02: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
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_get_original_destination(entry_connection_t *conn,
|
2006-08-10 11:01:37 +02:00
|
|
|
socks_request_t *req)
|
|
|
|
{
|
|
|
|
#ifdef TRANS_NETFILTER
|
|
|
|
/* Linux 2.4+ */
|
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
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST,
|
2006-08-10 11:01:37 +02:00
|
|
|
(struct sockaddr*)&orig_dst, &orig_dst_len) < 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;
|
|
|
|
}
|
|
|
|
|
2008-08-07 21:13:39 +02:00
|
|
|
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
|
|
|
|
tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
|
2006-08-10 11:01:37 +02:00
|
|
|
|
2006-08-10 11:02:26 +02:00
|
|
|
return 0;
|
|
|
|
#elif defined(TRANS_PF)
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:58:17 +02:00
|
|
|
tor_addr_to_str(req->address, &addr, sizeof(req->address), 0);
|
2006-08-10 11:01:37 +02:00
|
|
|
req->port = ntohs(pnl.rdport);
|
|
|
|
|
|
|
|
return 0;
|
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
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
IF_HAS_BUFFEREVENT(base_conn, {
|
|
|
|
struct evbuffer *input = bufferevent_get_input(base_conn->bufev);
|
2009-08-04 18:30:53 +02:00
|
|
|
sockshere = fetch_from_evbuffer_socks(input, socks,
|
|
|
|
options->TestSocks, options->SafeSocks);
|
|
|
|
}) ELSE_IF_NO_BUFFEREVENT {
|
2011-07-20 18:55:42 +02:00
|
|
|
sockshere = fetch_from_buf_socks(base_conn->inbuf, socks,
|
2009-08-04 18:30:53 +02:00
|
|
|
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
|
|
|
*/
|
2008-07-23 17:58:30 +02:00
|
|
|
static 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 ||
|
|
|
|
edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
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
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2011-07-20 18:55:42 +02:00
|
|
|
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;
|
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) {
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024 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". */
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024 this is a kludgy way to do this. */
|
2011-03-25 22:57:15 +01:00
|
|
|
tor_assert(circ->_base.timestamp_dirty);
|
|
|
|
circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
|
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
|
|
|
|
2005-02-22 01:53:08 +01:00
|
|
|
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
|
2006-07-23 09:37:35 +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;
|
2003-10-04 10:19:23 +02:00
|
|
|
|
2009-08-11 21:16:16 +02:00
|
|
|
log_info(LD_APP,
|
|
|
|
"Sending relay cell %d to begin stream %d.",
|
|
|
|
(int)ap_conn->use_begindir,
|
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;
|
2006-12-13 03:49:45 +01:00
|
|
|
if (begin_type == RELAY_COMMAND_BEGIN) {
|
2011-11-23 23:10:46 +01:00
|
|
|
#ifndef NON_ANONYMOUS_MODE_ENABLED
|
2006-12-13 03:49:45 +01:00
|
|
|
tor_assert(circ->build_state->onehop_tunnel == 0);
|
2011-11-23 23:10:46 +01:00
|
|
|
#endif
|
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;
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->s, 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 ?
|
|
|
|
(long)generic_buffer_len(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);
|
2006-07-23 09:37:35 +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) {
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024 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". */
|
2012-06-15 15:37:40 +02:00
|
|
|
/* XXXX024 this is a kludgy way to do this. */
|
2011-03-25 22:57:15 +01:00
|
|
|
tor_assert(circ->_base.timestamp_dirty);
|
|
|
|
circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
|
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 */
|
2011-10-11 17:47:13 +02:00
|
|
|
r = tor_addr_parse_PTR_name(&addr, a, AF_INET, 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 */
|
|
|
|
|
2011-07-20 18:55:42 +02:00
|
|
|
tor_free(base_conn->address); /* Maybe already set by dnsserv. */
|
|
|
|
base_conn->address = tor_strdup("(Tor_internal)");
|
|
|
|
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
|
2011-07-20 18:55:42 +02:00
|
|
|
base_conn->s, circ->_base.n_circ_id);
|
2008-04-22 19:21:12 +02:00
|
|
|
control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0);
|
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);
|
|
|
|
conn->session_group = session_group;
|
|
|
|
conn->isolation_flags = isolation_flags;
|
|
|
|
|
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 */
|
2004-04-03 00:23:15 +02:00
|
|
|
if (connection_ap_handshake_attach_circuit(conn) < 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);
|
2007-04-21 19:26:12 +02:00
|
|
|
return NULL;
|
2004-04-01 00:02:13 +02:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (ttl >= 0 && (answer_type == RESOLVED_TYPE_IPV4 ||
|
|
|
|
answer_type == RESOLVED_TYPE_HOSTNAME)) {
|
|
|
|
return; /* we already told the controller. */
|
|
|
|
} else 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,
|
2010-10-02 03:31:09 +02:00
|
|
|
cp, expires, NULL);
|
|
|
|
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,
|
|
|
|
cp, expires, NULL);
|
|
|
|
tor_free(cp);
|
|
|
|
} else {
|
|
|
|
control_event_address_mapped(conn->socks_request->address,
|
|
|
|
"<error>",
|
|
|
|
time(NULL)+ttl,
|
|
|
|
"error=yes");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
2011-07-20 18:55:42 +02:00
|
|
|
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,
|
|
|
|
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) {
|
|
|
|
uint32_t a = ntohl(get_uint32(answer));
|
|
|
|
if (a)
|
|
|
|
client_dns_set_addressmap(conn->socks_request->address, a,
|
|
|
|
conn->chosen_exit_name, ttl);
|
|
|
|
} 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);
|
2006-12-26 23:41:43 +01:00
|
|
|
client_dns_set_reverse_addressmap(conn->socks_request->address,
|
|
|
|
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 {
|
|
|
|
/* This must be a request from the controller. We already sent
|
|
|
|
* a mapaddress if there's a ttl. */
|
|
|
|
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
|
|
|
|
2005-03-17 13:38:37 +01:00
|
|
|
control_event_stream_status(conn,
|
2006-10-20 19:54:36 +02:00
|
|
|
status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
|
2006-10-20 19:54:43 +02:00
|
|
|
endreason);
|
2004-11-03 19:33:07 +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) {
|
2003-10-04 03:37:01 +02:00
|
|
|
buf[0] = 5; /* version 5 */
|
2005-03-17 13:38:37 +01:00
|
|
|
buf[1] = (char)status;
|
2003-10-04 03:37:01 +02:00
|
|
|
buf[2] = 0;
|
|
|
|
buf[3] = 1; /* ipv4 addr */
|
2003-11-18 09:20:19 +01:00
|
|
|
memset(buf+4,0,6); /* Set external addr/port to 0.
|
|
|
|
The spec doesn't seem to say what to do here. -RD */
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_write_to_buf(buf,10,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
|
|
|
}
|
|
|
|
|
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;
|
2004-10-12 17:52:09 +02:00
|
|
|
char *address=NULL;
|
|
|
|
uint16_t port;
|
2006-12-25 04:42:38 +01:00
|
|
|
or_circuit_t *or_circ = NULL;
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2004-04-15 02:03:48 +02:00
|
|
|
assert_circuit_ok(circ);
|
2006-12-25 04:42:38 +01:00
|
|
|
if (!CIRCUIT_IS_ORIGIN(circ))
|
|
|
|
or_circ = TO_OR_CIRCUIT(circ);
|
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)
|
|
|
|
return -1;
|
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;
|
|
|
|
}
|
|
|
|
|
2006-09-29 05:50:11 +02:00
|
|
|
if (rh.command == RELAY_COMMAND_BEGIN) {
|
|
|
|
if (!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
2006-10-20 21:11:12 +02:00
|
|
|
"Relay begin cell has no \\0. Closing.");
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_TORPROTOCOL, NULL);
|
2006-09-29 05:50:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2011-10-11 18:02:19 +02:00
|
|
|
if (tor_addr_port_split(LOG_PROTOCOL_WARN,
|
|
|
|
(char*)(cell->payload+RELAY_HEADER_SIZE),
|
|
|
|
&address,&port)<0) {
|
2006-09-29 05:50:11 +02:00
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
2006-10-20 21:11:12 +02:00
|
|
|
"Unable to parse addr:port in relay begin cell. Closing.");
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_TORPROTOCOL, NULL);
|
2006-09-29 05:50:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (port==0) {
|
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
2006-10-20 21:11:12 +02:00
|
|
|
"Missing port in relay begin cell. Closing.");
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_TORPROTOCOL, NULL);
|
2006-09-29 05:50:11 +02:00
|
|
|
tor_free(address);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-27 23:07:22 +02:00
|
|
|
if (or_circ && or_circ->p_conn && !options->AllowSingleHopExits &&
|
2010-03-11 04:43:23 +01:00
|
|
|
(or_circ->is_first_hop ||
|
|
|
|
(!connection_or_digest_is_known_relay(
|
|
|
|
or_circ->p_conn->identity_digest) &&
|
2010-09-27 23:07:22 +02:00
|
|
|
should_refuse_unknown_exits(options)))) {
|
2008-09-26 20:58:45 +02:00
|
|
|
/* Don't let clients use us as a single-hop proxy, unless the user
|
2010-03-11 04:43:23 +01:00
|
|
|
* has explicitly allowed that in the config. It attracts attackers
|
2006-10-01 22:50:11 +02:00
|
|
|
* and users who'd be better off with, well, single-hop proxies.
|
|
|
|
*/
|
2010-09-28 00:32:09 +02:00
|
|
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
2010-03-11 04:43:23 +01:00
|
|
|
"Attempt by %s to open a stream %s. Closing.",
|
|
|
|
safe_str(or_circ->p_conn->_base.address),
|
|
|
|
or_circ->is_first_hop ? "on first hop of circuit" :
|
|
|
|
"from unknown relay");
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
2010-03-11 04:43:23 +01:00
|
|
|
or_circ->is_first_hop ?
|
|
|
|
END_STREAM_REASON_TORPROTOCOL :
|
|
|
|
END_STREAM_REASON_MISC,
|
|
|
|
NULL);
|
2006-10-01 22:50:11 +02:00
|
|
|
tor_free(address);
|
|
|
|
return 0;
|
|
|
|
}
|
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,
|
|
|
|
END_STREAM_REASON_NOTDIRECTORY, NULL);
|
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
|
|
|
|
* caller might want to know whether his IP address has changed, and
|
|
|
|
* we might already have corrected _base.addr[ess] for the relay's
|
|
|
|
* canonical IP address. */
|
|
|
|
if (or_circ && or_circ->p_conn)
|
|
|
|
address = tor_dup_addr(&or_circ->p_conn->real_addr);
|
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,
|
|
|
|
END_STREAM_REASON_INTERNAL, NULL);
|
2006-03-16 00:36:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_EXIT,"Creating new exit connection.");
|
2008-09-06 00:09:44 +02:00
|
|
|
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. */
|
2009-07-14 22:24:50 +02:00
|
|
|
TO_CONN(n_stream)->dirreq_id = circ->dirreq_id;
|
2009-08-18 15:53:08 +02:00
|
|
|
|
2006-07-26 21:07:26 +02:00
|
|
|
n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2003-12-19 06:09:51 +01:00
|
|
|
n_stream->stream_id = rh.stream_id;
|
2006-07-26 21:07:26 +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) {
|
2006-07-23 09:37:35 +02:00
|
|
|
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
2007-08-11 16:13:25 +02:00
|
|
|
log_info(LD_REND,"begin is for rendezvous. configuring stream.");
|
2006-07-26 21:07:26 +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);
|
2006-07-23 09:37:35 +02:00
|
|
|
if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
|
2006-07-26 21:07:26 +02:00
|
|
|
n_stream->_base.port);
|
2008-12-12 21:30:42 +01:00
|
|
|
relay_send_end_cell_from_edge(rh.stream_id, circ,
|
|
|
|
END_STREAM_REASON_EXITPOLICY,
|
|
|
|
origin_circ->cpath->prev);
|
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);
|
2004-04-06 22:25:18 +02:00
|
|
|
return 0;
|
|
|
|
}
|
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);
|
|
|
|
|
2004-04-06 22:25:18 +02:00
|
|
|
connection_exit_connect(n_stream);
|
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);
|
2006-07-26 21:07:26 +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) {
|
2007-05-10 10:53:05 +02:00
|
|
|
tor_assert(or_circ);
|
2009-04-11 20:19:57 +02:00
|
|
|
if (or_circ->p_conn && !tor_addr_is_null(&or_circ->p_conn->real_addr))
|
2010-02-09 18:32:10 +01:00
|
|
|
tor_addr_copy(&n_stream->_base.addr, &or_circ->p_conn->real_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;
|
2010-12-14 01:34:01 +01:00
|
|
|
dummy_conn->_base.address = tor_strndup(
|
|
|
|
(char*)cell->payload+RELAY_HEADER_SIZE,
|
|
|
|
rh.length);
|
2006-07-26 21:07:26 +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. */
|
2006-07-26 21:07:26 +02:00
|
|
|
if (!dummy_conn->_base.marked_for_close)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
2008-06-11 03:14:23 +02:00
|
|
|
int socket_error = 0;
|
2003-09-13 00:45:31 +02:00
|
|
|
|
2006-07-26 21:07:26 +02:00
|
|
|
if (!connection_edge_is_rendezvous_stream(edge_conn) &&
|
|
|
|
router_compare_to_my_exit_policy(edge_conn)) {
|
2006-02-13 10:02:35 +01:00
|
|
|
log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
|
2009-12-15 23:23:36 +01:00
|
|
|
escaped_safe_str_client(conn->address), conn->port);
|
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
|
|
|
}
|
|
|
|
|
2008-08-05 22:08:19 +02:00
|
|
|
addr = &conn->addr;
|
2004-10-17 03:57:34 +02:00
|
|
|
port = conn->port;
|
|
|
|
|
2006-02-13 10:02:35 +01:00
|
|
|
log_debug(LD_EXIT,"about to try connecting");
|
2008-06-11 03:14:23 +02:00
|
|
|
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
|
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)) {
|
2005-12-14 21:40:40 +01:00
|
|
|
/* in case there are any queued data cells */
|
2007-03-04 21:11:46 +01:00
|
|
|
log_warn(LD_BUG,"newly connected conn had data waiting!");
|
2003-09-13 00:45:31 +02:00
|
|
|
// connection_start_writing(conn);
|
|
|
|
}
|
2009-08-11 21:16:16 +02:00
|
|
|
IF_HAS_NO_BUFFEREVENT(conn)
|
|
|
|
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)) {
|
|
|
|
/* rendezvous stream */
|
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 */
|
2008-08-05 22:08:19 +02:00
|
|
|
char connected_payload[20];
|
|
|
|
int connected_payload_len;
|
|
|
|
if (tor_addr_family(&conn->addr) == AF_INET) {
|
|
|
|
set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
|
|
|
|
connected_payload_len = 4;
|
|
|
|
} else {
|
|
|
|
memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
|
|
|
|
connected_payload_len = 16;
|
|
|
|
}
|
|
|
|
set_uint32(connected_payload+connected_payload_len,
|
2006-07-26 21:07:26 +02:00
|
|
|
htonl(dns_clip_ttl(edge_conn->address_ttl)));
|
2008-08-05 22:08:19 +02:00
|
|
|
connected_payload_len += 4;
|
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,
|
2008-08-05 22:08:19 +02:00
|
|
|
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
|
|
|
|
2007-05-13 11:25:06 +02:00
|
|
|
exitconn->_base.state = EXIT_CONN_STATE_OPEN;
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2011-11-24 19:01:56 +01:00
|
|
|
dirconn = dir_connection_new(tor_addr_family(&exitconn->_base.addr));
|
2006-09-29 05:50:11 +02:00
|
|
|
|
2010-02-09 18:32:10 +01:00
|
|
|
tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr);
|
2007-05-13 11:25:06 +02:00
|
|
|
dirconn->_base.port = 0;
|
2009-04-11 21:22:38 +02:00
|
|
|
dirconn->_base.address = tor_strdup(exitconn->_base.address);
|
2007-05-13 11:25:06 +02:00
|
|
|
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. */
|
2009-07-14 22:24:50 +02:00
|
|
|
TO_CONN(dirconn)->dirreq_id = TO_CONN(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
|
2006-07-26 21:07:26 +02:00
|
|
|
connection_edge_is_rendezvous_stream(edge_connection_t *conn)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(conn);
|
2009-01-04 20:47:21 +01:00
|
|
|
if (conn->rend_data)
|
2004-04-06 23:52:01 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-19 07:57:16 +01:00
|
|
|
/** Return 1 if router <b>exit</b> is likely to allow stream <b>conn</b>
|
|
|
|
* 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
|
2011-07-20 18:55:42 +02:00
|
|
|
connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
|
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);
|
2004-11-29 09:34:54 +01:00
|
|
|
tor_assert(exit);
|
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,
|
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
|
|
|
exit->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) {
|
2005-02-22 01:53:08 +01:00
|
|
|
struct in_addr in;
|
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;
|
2011-07-15 18:58:13 +02:00
|
|
|
if (tor_inet_aton(conn->socks_request->address, &in)) {
|
|
|
|
tor_addr_from_in(&addr, &in);
|
|
|
|
addrp = &addr;
|
|
|
|
}
|
2011-07-15 23:53:13 +02:00
|
|
|
r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,exit);
|
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. */
|
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
|
|
|
if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit))
|
2006-09-21 23:48:42 +02:00
|
|
|
return 0;
|
2004-06-17 20:13:09 +02:00
|
|
|
}
|
2011-07-07 17:52:13 +02:00
|
|
|
if (routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) {
|
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-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;
|
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 */
|
2007-11-29 16:25:04 +01:00
|
|
|
if (strlcpy(query, address, REND_SERVICE_ID_LEN_BASE32+1) >=
|
|
|
|
REND_SERVICE_ID_LEN_BASE32+1)
|
2004-11-29 09:34:54 +01:00
|
|
|
goto failed;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
const uint8_t iso = conn->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;
|
|
|
|
if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
|
|
|
|
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);
|
2011-07-06 22:03:47 +02:00
|
|
|
circ->session_group = conn->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;
|
|
|
|
if (conn->session_group != circ->session_group)
|
|
|
|
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;
|
|
|
|
|
|
|
|
if ((mixed & conn->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
|
|
|
}
|
|
|
|
|