Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
David Goulet
Tor
Commits
37088869
Commit
37088869
authored
Jun 17, 2004
by
Nick Mathewson
🥄
Browse files
Implement RESOLVE/RESOLVED cells and socks resolve code
svn:r1978
parent
dfaa5ce7
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/or/buffers.c
View file @
37088869
...
...
@@ -409,6 +409,9 @@ int fetch_from_buf_http(buf_t *buf,
return
1
;
}
#define SOCKS_COMMAND_CONNECT 0x01
#define SOCKS_COMMAND_RESOLVE 0xF0
/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
* of the forms
* - socks4: "socksheader username\\0"
...
...
@@ -467,8 +470,12 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
log_fn
(
LOG_DEBUG
,
"socks5: checking request"
);
if
(
buf
->
datalen
<
8
)
/* basic info plus >=2 for addr plus 2 for port */
return
0
;
/* not yet */
if
(
*
(
buf
->
mem
+
1
)
!=
1
)
{
/* not a connect? we don't support it. */
log_fn
(
LOG_WARN
,
"socks5: command %d not '1'. Rejecting."
,
*
(
buf
->
mem
+
1
));
req
->
command
=
(
unsigned
char
)
*
(
buf
->
mem
+
1
);
if
(
req
->
command
!=
SOCKS_COMMAND_CONNECT
&&
req
->
command
!=
SOCKS_COMMAND_RESOLVE
)
{
/* not a connect or resolve? we don't support it. */
log_fn
(
LOG_WARN
,
"socks5: command %d not recognized. Rejecting."
,
req
->
command
);
return
-
1
;
}
switch
(
*
(
buf
->
mem
+
3
))
{
/* address type */
...
...
@@ -516,14 +523,18 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
if
(
buf
->
datalen
<
SOCKS4_NETWORK_LEN
)
/* basic info available? */
return
0
;
/* not yet */
if
(
*
(
buf
->
mem
+
1
)
!=
1
)
{
/* not a connect? we don't support it. */
log_fn
(
LOG_WARN
,
"socks4: command %d not '1'. Rejecting."
,
*
(
buf
->
mem
+
1
));
req
->
command
=
(
unsigned
char
)
*
(
buf
->
mem
+
1
);
if
(
req
->
command
!=
SOCKS_COMMAND_CONNECT
&&
req
->
command
!=
SOCKS_COMMAND_RESOLVE
)
{
/* not a connect or resolve? we don't support it. */
log_fn
(
LOG_WARN
,
"socks4: command %d not recognized. Rejecting."
,
req
->
command
);
return
-
1
;
}
req
->
port
=
ntohs
(
*
(
uint16_t
*
)(
buf
->
mem
+
2
));
destip
=
ntohl
(
*
(
uint32_t
*
)(
buf
->
mem
+
4
));
if
(
!
req
->
port
||
!
destip
)
{
if
(
(
!
req
->
port
&&
req
->
command
!=
SOCKS_COMMAND_RESOLVE
)
||
!
destip
)
{
log_fn
(
LOG_WARN
,
"socks4: Port or DestIP is zero. Rejecting."
);
return
-
1
;
}
...
...
src/or/circuituse.c
View file @
37088869
...
...
@@ -73,7 +73,14 @@ static int circuit_is_acceptable(circuit_t *circ,
return
0
;
/* this circuit is screwed and doesn't know it yet */
}
if
(
purpose
==
CIRCUIT_PURPOSE_C_GENERAL
)
{
if
(
conn
->
socks_request
&&
conn
->
socks_request
->
command
==
SOCKS_COMMAND_RESOLVE
)
{
/* 0.0.7 servers and earlier don't support DNS resolution. There are no
* ORs running code before 0.0.7, so we only worry about 0.0.7. Once all
* servers are running 0.0.8, remove this check. */
if
(
!
strncmp
(
exitrouter
->
platform
,
"Tor 0.0.7"
,
9
))
return
0
;
}
else
if
(
purpose
==
CIRCUIT_PURPOSE_C_GENERAL
)
{
if
(
connection_ap_can_use_exit
(
conn
,
exitrouter
)
==
ADDR_POLICY_REJECTED
)
{
/* can't exit from this router */
return
0
;
...
...
@@ -618,10 +625,12 @@ circuit_get_open_circ_or_launch(connection_t *conn,
circuit_t
**
circp
)
{
circuit_t
*
circ
;
uint32_t
addr
;
int
is_resolve
;
tor_assert
(
conn
);
tor_assert
(
circp
);
tor_assert
(
conn
->
state
==
AP_CONN_STATE_CIRCUIT_WAIT
);
is_resolve
=
conn
->
socks_request
->
command
==
SOCKS_COMMAND_RESOLVE
;
circ
=
circuit_get_best
(
conn
,
1
,
desired_circuit_purpose
);
...
...
@@ -630,7 +639,8 @@ circuit_get_open_circ_or_launch(connection_t *conn,
return
1
;
/* we're happy */
}
if
(
!
connection_edge_is_rendezvous_stream
(
conn
))
{
/* general purpose circ */
/* Do we need to check exit policy? */
if
(
!
is_resolve
&&
!
connection_edge_is_rendezvous_stream
(
conn
))
{
addr
=
client_dns_lookup_entry
(
conn
->
socks_request
->
address
);
if
(
router_exit_policy_all_routers_reject
(
addr
,
conn
->
socks_request
->
port
))
{
log_fn
(
LOG_WARN
,
"No Tor server exists that allows exit to %s:%d. Rejecting."
,
...
...
@@ -742,10 +752,13 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
circ
->
timestamp_dirty
=
time
(
NULL
);
link_apconn_to_circ
(
conn
,
circ
);
connection_ap_handshake_send_begin
(
conn
,
circ
);
tor_assert
(
conn
->
socks_request
);
if
(
conn
->
socks_request
->
command
==
SOCKS_COMMAND_CONNECT
)
connection_ap_handshake_send_begin
(
conn
,
circ
);
else
connection_ap_handshake_send_resolve
(
conn
,
circ
);
return
1
;
}
else
{
/* we're a rendezvous conn */
circuit_t
*
rendcirc
=
NULL
,
*
introcirc
=
NULL
;
...
...
src/or/connection.c
View file @
37088869
...
...
@@ -1276,7 +1276,10 @@ void assert_connection_ok(connection_t *conn, time_t now)
}
else
{
tor_assert
(
!
conn
->
socks_request
);
}
if
(
conn
->
type
!=
CONN_TYPE_DIR
)
{
if
(
conn
->
type
==
CONN_TYPE_EXIT
)
{
tor_assert
(
conn
->
purpose
==
EXIT_PURPOSE_CONNECT
||
conn
->
purpose
==
EXIT_PURPOSE_RESOLVE
);
}
else
if
(
conn
->
type
!=
CONN_TYPE_DIR
)
{
tor_assert
(
!
conn
->
purpose
);
/* only used for dir types currently */
}
...
...
src/or/connection_edge.c
View file @
37088869
...
...
@@ -371,6 +371,23 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
return
sockshere
;
}
/* else socks handshake is done, continue processing */
if
(
socks
->
command
==
SOCKS_COMMAND_RESOLVE
)
{
/* Reply to resolves immediately if we can. */
if
(
strlen
(
socks
->
address
)
>
RELAY_PAYLOAD_SIZE
)
{
connection_ap_handshake_socks_resolved
(
conn
,
RESOLVED_TYPE_ERROR
,
0
,
NULL
);
conn
->
socks_request
->
has_finished
=
1
;
connection_mark_for_close
(
conn
);
}
uint32_t
answer
=
htonl
(
client_dns_lookup_entry
(
socks
->
address
));
if
(
answer
)
{
connection_ap_handshake_socks_resolved
(
conn
,
RESOLVED_TYPE_IPV4
,
4
,
(
char
*
)
&
answer
);
conn
->
socks_request
->
has_finished
=
1
;
connection_mark_for_close
(
conn
);
return
0
;
}
}
/* this call _modifies_ socks->address iff it's a hidden-service request */
if
(
rend_parse_rendezvous_address
(
socks
->
address
)
<
0
)
{
/* normal request */
...
...
@@ -487,6 +504,46 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
return
0
;
}
/** 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.
*/
int
connection_ap_handshake_send_resolve
(
connection_t
*
ap_conn
,
circuit_t
*
circ
)
{
int
payload_len
;
const
char
*
string_addr
;
tor_assert
(
ap_conn
->
type
==
CONN_TYPE_AP
);
tor_assert
(
ap_conn
->
state
==
AP_CONN_STATE_CIRCUIT_WAIT
);
tor_assert
(
ap_conn
->
socks_request
);
tor_assert
(
ap_conn
->
socks_request
->
command
==
SOCKS_COMMAND_RESOLVE
);
tor_assert
(
circ
->
purpose
==
CIRCUIT_PURPOSE_C_GENERAL
);
ap_conn
->
stream_id
=
get_unique_stream_id_by_circ
(
circ
);
if
(
ap_conn
->
stream_id
==
0
)
{
/* Don't send end: there is no 'other side' yet */
ap_conn
->
has_sent_end
=
1
;
connection_mark_for_close
(
ap_conn
);
circuit_mark_for_close
(
circ
);
return
-
1
;
}
string_addr
=
ap_conn
->
socks_request
->
address
;
payload_len
=
strlen
(
string_addr
);
tor_assert
(
strlen
(
string_addr
)
<=
RELAY_PAYLOAD_SIZE
);
log_fn
(
LOG_DEBUG
,
"Sending relay cell to begin stream %d."
,
ap_conn
->
stream_id
);
if
(
connection_edge_send_command
(
ap_conn
,
circ
,
RELAY_COMMAND_RESOLVE
,
string_addr
,
payload_len
,
ap_conn
->
cpath_layer
)
<
0
)
return
-
1
;
/* circuit is closed, don't continue */
ap_conn
->
state
=
AP_CONN_STATE_RESOLVE_WAIT
;
log_fn
(
LOG_INFO
,
"Address sent for resolve, ap socket %d, n_circ_id %d"
,
ap_conn
->
s
,
circ
->
n_circ_id
);
return
0
;
}
/** Make an AP connection_t, do a socketpair 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.
...
...
@@ -544,6 +601,59 @@ int connection_ap_make_bridge(char *address, uint16_t port) {
return
fd
[
1
];
}
void
connection_ap_handshake_socks_resolved
(
connection_t
*
conn
,
int
answer_type
,
int
answer_len
,
const
char
*
answer
)
{
char
buf
[
256
];
int
replylen
;
if
(
answer_type
==
RESOLVED_TYPE_IPV4
)
{
uint32_t
a
=
get_uint32
(
answer
);
client_dns_set_entry
(
conn
->
socks_request
->
address
,
ntohl
(
a
));
}
if
(
conn
->
socks_request
->
socks_version
==
4
)
{
buf
[
0
]
=
0x00
;
/* version */
if
(
answer_type
==
RESOLVED_TYPE_IPV4
&&
answer_len
==
4
)
{
buf
[
1
]
=
90
;
/* "Granted" */
set_uint16
(
buf
+
2
,
0
);
memcpy
(
buf
+
4
,
answer
,
4
);
/* address */
replylen
=
SOCKS4_NETWORK_LEN
;
}
else
{
buf
[
1
]
=
91
;
/* "error" */
memset
(
buf
+
2
,
0
,
6
);
replylen
=
SOCKS4_NETWORK_LEN
;
}
}
else
{
/* SOCKS5 */
buf
[
0
]
=
0x05
;
/* version */
if
(
answer_type
==
RESOLVED_TYPE_IPV4
&&
answer_len
==
4
)
{
buf
[
1
]
=
0
;
/* succeeded */
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
)
{
buf
[
1
]
=
0
;
/* succeeded */
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
;
}
else
{
buf
[
1
]
=
0x04
;
/* host unreachable */
memset
(
buf
+
2
,
0
,
8
);
replylen
=
10
;
}
}
connection_ap_handshake_socks_reply
(
conn
,
buf
,
replylen
,
answer_type
==
RESOLVED_TYPE_IPV4
||
answer_type
==
RESOLVED_TYPE_IPV6
);
}
/** Send a socks reply to stream <b>conn</b>, using the appropriate
* socks version, etc.
*
...
...
@@ -631,6 +741,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
log_fn
(
LOG_DEBUG
,
"Creating new exit connection."
);
n_stream
=
connection_new
(
CONN_TYPE_EXIT
);
n_stream
->
purpose
=
EXIT_PURPOSE_CONNECT
;
n_stream
->
stream_id
=
rh
.
stream_id
;
n_stream
->
port
=
atoi
(
colon
+
1
);
...
...
@@ -694,6 +805,52 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
return
0
;
}
/**
* Called when we receive a RELAY_RESOLVE cell 'cell' along the circuit 'circ';
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
*/
int
connection_exit_begin_resolve
(
cell_t
*
cell
,
circuit_t
*
circ
)
{
connection_t
*
dummy_conn
;
relay_header_t
rh
;
assert_circuit_ok
(
circ
);
relay_header_unpack
(
&
rh
,
cell
->
payload
);
/* 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.)
*/
dummy_conn
=
connection_new
(
CONN_TYPE_EXIT
);
dummy_conn
->
stream_id
=
rh
.
stream_id
;
dummy_conn
->
address
=
tor_strndup
(
cell
->
payload
+
RELAY_HEADER_SIZE
,
rh
.
length
);
dummy_conn
->
port
=
0
;
dummy_conn
->
state
=
EXIT_CONN_STATE_RESOLVEFAILED
;
dummy_conn
->
purpose
=
EXIT_PURPOSE_RESOLVE
;
/* send it off to the gethostbyname farm */
switch
(
dns_resolve
(
dummy_conn
))
{
case
1
:
/* resolve worked; resolved cell was sent. */
connection_free
(
dummy_conn
);
return
0
;
case
-
1
:
/* resolve failed; resolved cell was sent. */
log_fn
(
LOG_INFO
,
"Resolve failed (%s)."
,
dummy_conn
->
address
);
connection_free
(
dummy_conn
);
break
;
case
0
:
/* resolve added to pending list */
/* add it into the linked list of resolving_streams on this circuit */
dummy_conn
->
next_stream
=
circ
->
resolving_streams
;
circ
->
resolving_streams
=
dummy_conn
;
assert_circuit_ok
(
circ
);
;
}
return
0
;
}
/** Connect to conn's specified addr and port. If it worked, conn
* has now been added to the connection_array.
*
...
...
@@ -776,6 +933,12 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
log_fn
(
LOG_DEBUG
,
"considering nickname %s, for address %s / port %d:"
,
exit
->
nickname
,
conn
->
socks_request
->
address
,
conn
->
socks_request
->
port
);
if
(
conn
->
socks_request
->
command
==
SOCKS_COMMAND_RESOLVE
)
{
/* 0.0.7 servers and earlier don't support DNS resolution. There are no
* ORs running code before 0.0.7, so we only worry about 0.0.7. Once all
* servers are running 0.0.8, remove this check. */
return
strncmp
(
exit
->
platform
,
"Tor 0.0.7"
,
9
)
?
1
:
0
;
}
addr
=
client_dns_lookup_entry
(
conn
->
socks_request
->
address
);
return
router_compare_addr_to_exit_policy
(
addr
,
conn
->
socks_request
->
port
,
exit
->
exit_policy
);
...
...
src/or/dns.c
View file @
37088869
...
...
@@ -71,6 +71,7 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome);
static
int
dnsworker_main
(
void
*
data
);
static
int
spawn_dnsworker
(
void
);
static
void
spawn_enough_dnsworkers
(
void
);
static
void
send_resolved_cell
(
connection_t
*
conn
,
uint8_t
answer_type
);
/** Splay tree of cached_resolve objects. */
static
SPLAY_HEAD
(
cache_tree
,
cached_resolve
)
cache_root
;
...
...
@@ -141,6 +142,34 @@ static void purge_expired_resolves(uint32_t now) {
}
}
static
void
send_resolved_cell
(
connection_t
*
conn
,
uint8_t
answer_type
)
{
char
buf
[
RELAY_PAYLOAD_SIZE
];
int
buflen
;
buf
[
0
]
=
answer_type
;
switch
(
answer_type
)
{
case
RESOLVED_TYPE_IPV4
:
buf
[
1
]
=
4
;
set_uint32
(
buf
+
2
,
htonl
(
conn
->
addr
));
buflen
=
6
;
break
;
case
RESOLVED_TYPE_ERROR_TRANSIENT
:
case
RESOLVED_TYPE_ERROR
:
buf
[
1
]
=
24
;
/* length of "error resolving hostname" */
strcpy
(
buf
+
2
,
"error resolving hostname"
);
buflen
=
26
;
break
;
default:
tor_assert
(
0
);
}
connection_edge_send_command
(
conn
,
circuit_get_by_conn
(
conn
),
RELAY_COMMAND_RESOLVED
,
buf
,
buflen
,
conn
->
cpath_layer
);
}
/** See if we have a cache entry for <b>exitconn</b>-\>address. if so,
* if resolve valid, put it into <b>exitconn</b>-\>addr and return 1.
* If resolve failed, return -1.
...
...
@@ -179,7 +208,8 @@ int dns_resolve(connection_t *exitconn) {
switch
(
resolve
->
state
)
{
case
CACHE_STATE_PENDING
:
/* add us to the pending list */
pending_connection
=
tor_malloc
(
sizeof
(
struct
pending_connection_t
));
pending_connection
=
tor_malloc_zero
(
sizeof
(
struct
pending_connection_t
));
pending_connection
->
conn
=
exitconn
;
pending_connection
->
next
=
resolve
->
pending_connections
;
resolve
->
pending_connections
=
pending_connection
;
...
...
@@ -191,8 +221,12 @@ int dns_resolve(connection_t *exitconn) {
exitconn
->
addr
=
resolve
->
addr
;
log_fn
(
LOG_DEBUG
,
"Connection (fd %d) found cached answer for '%s'"
,
exitconn
->
s
,
exitconn
->
address
);
if
(
exitconn
->
purpose
==
EXIT_PURPOSE_RESOLVE
)
send_resolved_cell
(
exitconn
,
RESOLVED_TYPE_IPV4
);
return
1
;
case
CACHE_STATE_FAILED
:
if
(
exitconn
->
purpose
==
EXIT_PURPOSE_RESOLVE
)
send_resolved_cell
(
exitconn
,
RESOLVED_TYPE_ERROR
);
return
-
1
;
}
tor_assert
(
0
);
...
...
@@ -205,7 +239,7 @@ int dns_resolve(connection_t *exitconn) {
resolve
->
address
[
MAX_ADDRESSLEN
-
1
]
=
0
;
/* add us to the pending list */
pending_connection
=
tor_malloc
(
sizeof
(
struct
pending_connection_t
));
pending_connection
=
tor_malloc
_zero
(
sizeof
(
struct
pending_connection_t
));
pending_connection
->
conn
=
exitconn
;
pending_connection
->
next
=
NULL
;
resolve
->
pending_connections
=
pending_connection
;
...
...
@@ -240,6 +274,7 @@ static int assign_to_dnsworker(connection_t *exitconn) {
if
(
!
dnsconn
)
{
log_fn
(
LOG_WARN
,
"no idle dns workers. Failing."
);
dns_cancel_pending_resolve
(
exitconn
->
address
);
send_resolved_cell
(
exitconn
,
RESOLVED_TYPE_ERROR_TRANSIENT
);
return
-
1
;
}
...
...
@@ -453,28 +488,42 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) {
pend
=
resolve
->
pending_connections
;
assert_connection_ok
(
pend
->
conn
,
time
(
NULL
));
pend
->
conn
->
addr
=
resolve
->
addr
;
pendconn
=
pend
->
conn
;
/* don't pass complex things to the
connection_mark_for_close macro */
if
(
resolve
->
state
==
CACHE_STATE_FAILED
)
{
pendconn
=
pend
->
conn
;
/* don't pass complex things to the
connection_mark_for_close macro */
/* prevent double-remove. */
pendconn
->
state
=
EXIT_CONN_STATE_RESOLVEFAILED
;
circuit_detach_stream
(
circuit_get_by_conn
(
pendconn
),
pendconn
);
connection_edge_end
(
pendconn
,
END_STREAM_REASON_MISC
,
pendconn
->
cpath_layer
);
if
(
pendconn
->
purpose
==
EXIT_PURPOSE_CONNECT
)
connection_edge_end
(
pendconn
,
END_STREAM_REASON_MISC
,
pendconn
->
cpath_layer
);
else
send_resolved_cell
(
pendconn
,
RESOLVED_TYPE_ERROR
);
connection_free
(
pendconn
);
}
else
{
/* prevent double-remove. */
pend
->
conn
->
state
=
EXIT_CONN_STATE_CONNECTING
;
circ
=
circuit_get_by_conn
(
pend
->
conn
);
assert
(
circ
);
/* unlink pend->conn from resolving_streams, */
circuit_detach_stream
(
circ
,
pend
->
conn
);
/* and link it to n_streams */
pend
->
conn
->
next_stream
=
circ
->
n_streams
;
circ
->
n_streams
=
pend
->
conn
;
connection_exit_connect
(
pend
->
conn
);
if
(
pendconn
->
purpose
==
EXIT_PURPOSE_CONNECT
)
{
/* prevent double-remove. */
pend
->
conn
->
state
=
EXIT_CONN_STATE_CONNECTING
;
circ
=
circuit_get_by_conn
(
pend
->
conn
);
tor_assert
(
circ
);
/* unlink pend->conn from resolving_streams, */
circuit_detach_stream
(
circ
,
pend
->
conn
);
/* and link it to n_streams */
pend
->
conn
->
next_stream
=
circ
->
n_streams
;
circ
->
n_streams
=
pend
->
conn
;
connection_exit_connect
(
pend
->
conn
);
}
else
{
/* prevent double-remove. This isn't really an accurate state,
* but it does the right thing. */
pendconn
->
state
=
EXIT_CONN_STATE_RESOLVEFAILED
;
send_resolved_cell
(
pendconn
,
RESOLVED_TYPE_IPV4
);
circ
=
circuit_get_by_conn
(
pendconn
);
tor_assert
(
circ
);
circuit_detach_stream
(
circ
,
pendconn
);
connection_free
(
pendconn
);
}
}
resolve
->
pending_connections
=
pend
->
next
;
tor_free
(
pend
);
...
...
src/or/or.h
View file @
37088869
...
...
@@ -221,9 +221,11 @@
#define AP_CONN_STATE_CIRCUIT_WAIT 7
/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */
#define AP_CONN_STATE_CONNECT_WAIT 8
/** State for a SOCKS connection: send RESOLVE, waiting for RESOLVED. */
#define AP_CONN_STATE_RESOLVE_WAIT 9
/** State for a SOCKS connection: ready to send and receive. */
#define AP_CONN_STATE_OPEN
9
#define _AP_CONN_STATE_MAX
9
#define AP_CONN_STATE_OPEN
10
#define _AP_CONN_STATE_MAX
10
#define _DIR_CONN_STATE_MIN 1
/** State for connection to directory server: waiting for connect(). */
...
...
@@ -259,6 +261,11 @@
#define DIR_PURPOSE_SERVER 7
#define _DIR_PURPOSE_MAX 7
#define _EXIT_PURPOSE_MIN 1
#define EXIT_PURPOSE_CONNECT 1
#define EXIT_PURPOSE_RESOLVE 2
#define _EXIT_PURPOSE_MAX 2
/** Circuit state: I'm the OP, still haven't done all my handshakes. */
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
...
...
@@ -371,6 +378,11 @@
#define END_STREAM_REASON_TIMEOUT 7
#define _MAX_END_STREAM_REASON 7
#define RESOLVED_TYPE_IPV4 4
#define RESOLVED_TYPE_IPV6 6
#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
#define RESOLVED_TYPE_ERROR 0xF1
/** Length of 'y' portion of 'y.onion' URL. */
#define REND_SERVICE_ID_LEN 16
...
...
@@ -841,9 +853,12 @@ typedef struct {
/* XXX are these good enough defaults? */
#define MAX_SOCKS_REPLY_LEN 1024
#define MAX_SOCKS_ADDR_LEN 256
#define SOCKS_COMMAND_CONNECT 0x01
#define SOCKS_COMMAND_RESOLVE 0xF0
/** State of a SOCKS request from a user to an OP */
struct
socks_request_t
{
char
socks_version
;
/**< Which version of SOCKS did the client use? */
int
command
;
/**< What has the user requested? One of CONNECT or RESOLVE. */
int
replylen
;
/**< Length of <b>reply</b>. */
char
reply
[
MAX_SOCKS_REPLY_LEN
];
/**< Write an entry into this string if
* we want to specify our own socks reply,
...
...
@@ -1048,13 +1063,18 @@ int connection_edge_finished_flushing(connection_t *conn);
int
connection_edge_finished_connecting
(
connection_t
*
conn
);
int
connection_ap_handshake_send_begin
(
connection_t
*
ap_conn
,
circuit_t
*
circ
);
int
connection_ap_handshake_send_resolve
(
connection_t
*
ap_conn
,
circuit_t
*
circ
);
int
connection_ap_make_bridge
(
char
*
address
,
uint16_t
port
);
void
connection_ap_handshake_socks_reply
(
connection_t
*
conn
,
char
*
reply
,
int
replylen
,
char
success
);
void
connection_ap_handshake_socks_resolved
(
connection_t
*
conn
,
int
answer_type
,
int
answer_len
,
const
char
*
answer
);
int
connection_exit_begin_conn
(
cell_t
*
cell
,
circuit_t
*
circ
);
int
connection_exit_begin_resolve
(
cell_t
*
cell
,
circuit_t
*
circ
);
void
connection_exit_connect
(
connection_t
*
conn
);
int
connection_edge_is_rendezvous_stream
(
connection_t
*
conn
);
int
connection_ap_can_use_exit
(
connection_t
*
conn
,
routerinfo_t
*
exit
);
...
...
src/or/relay.c
View file @
37088869
...
...
@@ -562,6 +562,26 @@ connection_edge_process_relay_cell_not_open(
}
return
0
;
}
if
(
conn
->
type
==
CONN_TYPE_AP
&&
rh
->
command
==
RELAY_COMMAND_RESOLVED
)
{
if
(
conn
->
state
!=
AP_CONN_STATE_RESOLVE_WAIT
)
{
log_fn
(
LOG_WARN
,
"Got a 'resolved' cell while not in state resolve_wait. Dropping."
);
return
0
;
}
tor_assert
(
conn
->
socks_request
->
command
==
SOCKS_COMMAND_RESOLVE
);
if
(
rh
->
length
<
2
||
cell
->
payload
[
RELAY_HEADER_SIZE
+
1
]
+
2
>
rh
->
length
)
{
log_fn
(
LOG_WARN
,
"Dropping malformed 'resolved' cell"
);
connection_edge_end
(
conn
,
END_STREAM_REASON_MISC
,
conn
->
cpath_layer
);
connection_mark_for_close
(
conn
);
return
0
;
}
connection_ap_handshake_socks_resolved
(
conn
,
cell
->
payload
[
RELAY_HEADER_SIZE
],
/*answer_type*/
cell
->
payload
[
RELAY_HEADER_SIZE
+
1
],
/*answer_len*/
cell
->
payload
+
RELAY_HEADER_SIZE
+
2
);
/* answer */
conn
->
socks_request
->
has_finished
=
1
;
connection_mark_for_close
(
conn
);
return
0
;
}
log_fn
(
LOG_WARN
,
"Got an unexpected relay command %d, in state %d (%s). Closing."
,
rh
->
command
,
conn
->
state
,
conn_state_to_string
[
conn
->
type
][
conn
->
state
]);
...
...
@@ -744,6 +764,27 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
connection_start_reading
(
conn
);
connection_edge_package_raw_inbuf
(
conn
);
/* handle whatever might still be on the inbuf */
return
0
;
case
RELAY_COMMAND_RESOLVE
:
if
(
layer_hint
)
{
log_fn
(
LOG_WARN
,
"resolve request unsupported at AP; dropping."
);
return
0
;
}
else
if
(
conn
)
{
log_fn
(
LOG_WARN
,
"resolve request for known stream; dropping."
);
return
0
;
}
else
if
(
circ
->
purpose
!=
CIRCUIT_PURPOSE_OR
)
{
log_fn
(
LOG_WARN
,
"resolve request on circ with purpose %d; dropping"
,
circ
->
purpose
);
return
0
;
}
connection_exit_begin_resolve
(
cell
,
circ
);
return
0
;
case
RELAY_COMMAND_RESOLVED
:
if
(
conn
)
{
log_fn
(
LOG_WARN
,
"'resolved' unsupported while open. Closing circ."
);
return
-
1
;
}
log_fn
(
LOG_INFO
,
"'resolved' received, no conn attached anymore. Ignoring."
);
return
0
;
case
RELAY_COMMAND_ESTABLISH_INTRO
:
case
RELAY_COMMAND_ESTABLISH_RENDEZVOUS
:
case
RELAY_COMMAND_INTRODUCE1
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment