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
Mike Perry
Tor
Commits
4b30ae15
Commit
4b30ae15
authored
Aug 20, 2017
by
Nick Mathewson
👁
Browse files
Add support for HTTP Connect tunnels
parent
eda79c2f
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/or/config.c
View file @
4b30ae15
...
...
@@ -372,6 +372,7 @@ static config_var_t option_vars_[] = {
V
(
HTTPProxyAuthenticator
,
STRING
,
NULL
),
V
(
HTTPSProxy
,
STRING
,
NULL
),
V
(
HTTPSProxyAuthenticator
,
STRING
,
NULL
),
VPORT
(
HTTPTunnelPort
),
V
(
IPv6Exit
,
BOOL
,
"0"
),
VAR
(
"ServerTransportPlugin"
,
LINELIST
,
ServerTransportPlugin
,
NULL
),
V
(
ServerTransportListenAddr
,
LINELIST
,
NULL
),
...
...
@@ -2910,7 +2911,8 @@ options_validate_single_onion(or_options_t *options, char **msg)
const
int
client_port_set
=
(
options
->
SocksPort_set
||
options
->
TransPort_set
||
options
->
NATDPort_set
||
options
->
DNSPort_set
);
options
->
DNSPort_set
||
options
->
HTTPTunnelPort_set
);
if
(
rend_service_non_anonymous_mode_enabled
(
options
)
&&
client_port_set
&&
!
options
->
Tor2webMode
)
{
REJECT
(
"HiddenServiceNonAnonymousMode is incompatible with using Tor as "
...
...
@@ -6976,6 +6978,15 @@ parse_ports(or_options_t *options, int validate_only,
*
msg
=
tor_strdup
(
"Invalid NatdPort configuration"
);
goto
err
;
}
if
(
parse_port_config
(
ports
,
options
->
HTTPTunnelPort_lines
,
"HTTP Tunnel"
,
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
,
"127.0.0.1"
,
0
,
((
validate_only
?
0
:
CL_PORT_WARN_NONLOCAL
)
|
CL_PORT_TAKES_HOSTNAMES
|
gw_flag
))
<
0
)
{
*
msg
=
tor_strdup
(
"Invalid HTTPTunnelPort configuration"
);
goto
err
;
}
{
unsigned
control_port_flags
=
CL_PORT_NO_STREAM_OPTIONS
|
CL_PORT_WARN_NONLOCAL
;
...
...
@@ -7053,6 +7064,8 @@ parse_ports(or_options_t *options, int validate_only,
!!
count_real_listeners
(
ports
,
CONN_TYPE_AP_TRANS_LISTENER
,
1
);
options
->
NATDPort_set
=
!!
count_real_listeners
(
ports
,
CONN_TYPE_AP_NATD_LISTENER
,
1
);
options
->
HTTPTunnelPort_set
=
!!
count_real_listeners
(
ports
,
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
,
1
);
/* Use options->ControlSocket to test if a control socket is set */
options
->
ControlPort_set
=
!!
count_real_listeners
(
ports
,
CONN_TYPE_CONTROL_LISTENER
,
0
);
...
...
src/or/connection.c
View file @
4b30ae15
...
...
@@ -158,7 +158,8 @@ static smartlist_t *outgoing_addrs = NULL;
case CONN_TYPE_CONTROL_LISTENER: \
case CONN_TYPE_AP_TRANS_LISTENER: \
case CONN_TYPE_AP_NATD_LISTENER: \
case CONN_TYPE_AP_DNS_LISTENER
case CONN_TYPE_AP_DNS_LISTENER: \
case CONN_TYPE_AP_HTTP_CONNECT_LISTENER
/**************************************************************/
...
...
@@ -185,6 +186,7 @@ conn_type_to_string(int type)
case
CONN_TYPE_CONTROL
:
return
"Control"
;
case
CONN_TYPE_EXT_OR
:
return
"Extended OR"
;
case
CONN_TYPE_EXT_OR_LISTENER
:
return
"Extended OR listener"
;
case
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
:
return
"HTTP tunnel listener"
;
default:
log_warn
(
LD_BUG
,
"unknown connection type %d"
,
type
);
tor_snprintf
(
buf
,
sizeof
(
buf
),
"unknown [%d]"
,
type
);
...
...
@@ -1702,6 +1704,8 @@ connection_init_accepted_conn(connection_t *conn,
TO_ENTRY_CONN
(
conn
)
->
is_transparent_ap
=
1
;
conn
->
state
=
AP_CONN_STATE_NATD_WAIT
;
break
;
case
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
:
conn
->
state
=
AP_CONN_STATE_HTTP_CONNECT_WAIT
;
}
break
;
case
CONN_TYPE_DIR
:
...
...
@@ -3394,6 +3398,7 @@ connection_handle_read_impl(connection_t *conn)
case
CONN_TYPE_AP_LISTENER
:
case
CONN_TYPE_AP_TRANS_LISTENER
:
case
CONN_TYPE_AP_NATD_LISTENER
:
case
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
:
return
connection_handle_listener_read
(
conn
,
CONN_TYPE_AP
);
case
CONN_TYPE_DIR_LISTENER
:
return
connection_handle_listener_read
(
conn
,
CONN_TYPE_DIR
);
...
...
@@ -4286,6 +4291,7 @@ connection_is_listener(connection_t *conn)
conn
->
type
==
CONN_TYPE_AP_TRANS_LISTENER
||
conn
->
type
==
CONN_TYPE_AP_DNS_LISTENER
||
conn
->
type
==
CONN_TYPE_AP_NATD_LISTENER
||
conn
->
type
==
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
||
conn
->
type
==
CONN_TYPE_DIR_LISTENER
||
conn
->
type
==
CONN_TYPE_CONTROL_LISTENER
)
return
1
;
...
...
src/or/connection_edge.c
View file @
4b30ae15
...
...
@@ -127,6 +127,7 @@
static
int
connection_ap_handshake_process_socks
(
entry_connection_t
*
conn
);
static
int
connection_ap_process_natd
(
entry_connection_t
*
conn
);
static
int
connection_ap_process_http_connect
(
entry_connection_t
*
conn
);
static
int
connection_exit_connect_dir
(
edge_connection_t
*
exitconn
);
static
int
consider_plaintext_ports
(
entry_connection_t
*
conn
,
uint16_t
port
);
static
int
connection_ap_supports_optimistic_data
(
const
entry_connection_t
*
);
...
...
@@ -237,6 +238,11 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
return
-
1
;
}
return
0
;
case
AP_CONN_STATE_HTTP_CONNECT_WAIT
:
if
(
connection_ap_process_http_connect
(
EDGE_TO_ENTRY_CONN
(
conn
))
<
0
)
{
return
-
1
;
}
return
0
;
case
AP_CONN_STATE_OPEN
:
case
EXIT_CONN_STATE_OPEN
:
if
(
connection_edge_package_raw_inbuf
(
conn
,
package_partial
,
NULL
)
<
0
)
{
...
...
@@ -486,6 +492,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
case
AP_CONN_STATE_CONNECT_WAIT
:
case
AP_CONN_STATE_CONTROLLER_WAIT
:
case
AP_CONN_STATE_RESOLVE_WAIT
:
case
AP_CONN_STATE_HTTP_CONNECT_WAIT
:
return
0
;
default:
log_warn
(
LD_BUG
,
"Called in unexpected state %d."
,
conn
->
base_
.
state
);
...
...
@@ -2349,6 +2356,95 @@ connection_ap_process_natd(entry_connection_t *conn)
return
connection_ap_rewrite_and_attach_if_allowed
(
conn
,
NULL
,
NULL
);
}
/** Called on an HTTP CONNECT entry connection when some bytes have arrived,
* but we have not yet received a full HTTP CONNECT request. Try to parse an
* HTTP CONNECT request from the connection's inbuf. On success, set up the
* connection's socks_request field and try to attach the connection. On
* failure, send an HTTP reply, and mark the connection.
*/
static
int
connection_ap_process_http_connect
(
entry_connection_t
*
conn
)
{
if
(
BUG
(
ENTRY_TO_CONN
(
conn
)
->
state
!=
AP_CONN_STATE_HTTP_CONNECT_WAIT
))
return
-
1
;
char
*
headers
=
NULL
,
*
body
=
NULL
;
char
*
command
=
NULL
,
*
addrport
=
NULL
;
char
*
addr
=
NULL
;
size_t
bodylen
=
0
;
const
char
*
errmsg
=
NULL
;
int
rv
=
0
;
const
int
http_status
=
fetch_from_buf_http
(
ENTRY_TO_CONN
(
conn
)
->
inbuf
,
&
headers
,
8192
,
&
body
,
&
bodylen
,
1024
,
0
);
if
(
http_status
<
0
)
{
/* Bad http status */
errmsg
=
"HTTP/1.0 400 Bad Request
\r\n\r\n
"
;
goto
err
;
}
else
if
(
http_status
==
0
)
{
/* no HTTP request yet. */
goto
done
;
}
const
int
cmd_status
=
parse_http_command
(
headers
,
&
command
,
&
addrport
);
if
(
cmd_status
<
0
)
{
errmsg
=
"HTTP/1.0 400 Bad Request
\r\n\r\n
"
;
goto
err
;
}
tor_assert
(
command
);
tor_assert
(
addrport
);
if
(
strcasecmp
(
command
,
"connect"
))
{
errmsg
=
"HTTP/1.0 405 Method Not Allowed
\r\n\r\n
"
;
goto
err
;
}
tor_assert
(
conn
->
socks_request
);
socks_request_t
*
socks
=
conn
->
socks_request
;
uint16_t
port
;
if
(
tor_addr_port_split
(
LOG_WARN
,
addrport
,
&
addr
,
&
port
)
<
0
)
{
errmsg
=
"HTTP/1.0 400 Bad Request
\r\n\r\n
"
;
goto
err
;
}
if
(
strlen
(
addr
)
>=
MAX_SOCKS_ADDR_LEN
)
{
errmsg
=
"HTTP/1.0 414 Request-URI Too Long
\r\n\r\n
"
;
goto
err
;
}
/* XXXX Look at headers */
socks
->
command
=
SOCKS_COMMAND_CONNECT
;
socks
->
listener_type
=
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
;
strlcpy
(
socks
->
address
,
addr
,
sizeof
(
socks
->
address
));
socks
->
port
=
port
;
control_event_stream_status
(
conn
,
STREAM_EVENT_NEW
,
0
);
rv
=
connection_ap_rewrite_and_attach_if_allowed
(
conn
,
NULL
,
NULL
);
// XXXX send a "100 Continue" message?
goto
done
;
err:
if
(
BUG
(
errmsg
==
NULL
))
errmsg
=
"HTTP/1.0 400 Bad Request
\r\n\r\n
"
;
log_warn
(
LD_EDGE
,
"Saying %s"
,
escaped
(
errmsg
));
connection_write_to_buf
(
errmsg
,
strlen
(
errmsg
),
ENTRY_TO_CONN
(
conn
));
connection_mark_unattached_ap
(
conn
,
END_STREAM_REASON_HTTPPROTOCOL
|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED
);
done:
tor_free
(
headers
);
tor_free
(
body
);
tor_free
(
command
);
tor_free
(
addrport
);
tor_free
(
addr
);
return
rv
;
}
/** 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.
*/
...
...
@@ -2972,7 +3068,14 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
conn
->
socks_request
->
has_finished
=
1
;
return
;
}
if
(
conn
->
socks_request
->
socks_version
==
4
)
{
if
(
conn
->
socks_request
->
listener_type
==
CONN_TYPE_AP_HTTP_CONNECT_LISTENER
)
{
const
char
*
response
=
end_reason_to_http_connect_response_line
(
endreason
);
if
(
!
response
)
{
response
=
"HTTP/1.0 400 Bad Request
\r\n\r\n
"
;
}
connection_write_to_buf
(
response
,
strlen
(
response
),
ENTRY_TO_CONN
(
conn
));
}
else
if
(
conn
->
socks_request
->
socks_version
==
4
)
{
memset
(
buf
,
0
,
SOCKS4_NETWORK_LEN
);
buf
[
1
]
=
(
status
==
SOCKS5_SUCCEEDED
?
SOCKS4_GRANTED
:
SOCKS4_REJECT
);
/* leave version, destport, destip zero */
...
...
src/or/networkstatus.c
View file @
4b30ae15
...
...
@@ -1683,7 +1683,8 @@ any_client_port_set(const or_options_t *options)
options
->
TransPort_set
||
options
->
NATDPort_set
||
options
->
ControlPort_set
||
options
->
DNSPort_set
);
options
->
DNSPort_set
||
options
->
HTTPTunnelPort_set
);
}
/**
...
...
src/or/or.h
View file @
4b30ae15
...
...
@@ -226,8 +226,10 @@ typedef enum {
#define CONN_TYPE_EXT_OR 16
/** Type for sockets listening for Extended ORPort connections. */
#define CONN_TYPE_EXT_OR_LISTENER 17
/** Type for sockets listening for HTTP CONNECT tunnel connections. */
#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18
#define CONN_TYPE_MAX_ 1
7
#define CONN_TYPE_MAX_ 1
9
/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
* connection_t. */
...
...
@@ -348,7 +350,9 @@ typedef enum {
/** State for a transparent natd connection: waiting for original
* destination. */
#define AP_CONN_STATE_NATD_WAIT 12
#define AP_CONN_STATE_MAX_ 12
/** State for an HTTP tunnel: waiting for an HTTP CONNECT command. */
#define AP_CONN_STATE_HTTP_CONNECT_WAIT 13
#define AP_CONN_STATE_MAX_ 13
/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding
* edge connection is not attached to any circuit. */
...
...
@@ -645,6 +649,10 @@ typedef enum {
/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1);
* you don't want to do that over a randomly chosen exit */
#define END_STREAM_REASON_PRIVATE_ADDR 262
/** This is an HTTP tunnel connection and the client used or misused HTTP in a
* way we can't handle.
*/
#define END_STREAM_REASON_HTTPPROTOCOL 263
/** Bitwise-and this value with endreason to mask out all flags. */
#define END_STREAM_REASON_MASK 511
...
...
@@ -3693,6 +3701,8 @@ typedef struct {
}
TransProxyType_parsed
;
config_line_t
*
NATDPort_lines
;
/**< Ports to listen on for transparent natd
* connections. */
/** Ports to listen on for HTTP Tunnel connections. */
config_line_t
*
HTTPTunnelPort_lines
;
config_line_t
*
ControlPort_lines
;
/**< Ports to listen on for control
* connections. */
config_line_t
*
ControlSocket
;
/**< List of Unix Domain Sockets to listen on
...
...
@@ -3719,7 +3729,8 @@ typedef struct {
* configured in one of the _lines options above.
* For client ports, also true if there is a unix socket configured.
* If you are checking for client ports, you may want to use:
* SocksPort_set || TransPort_set || NATDPort_set || DNSPort_set
* SocksPort_set || TransPort_set || NATDPort_set || DNSPort_set ||
* HTTPTunnelPort_set
* rather than SocksPort_set.
*
* @{
...
...
@@ -3732,6 +3743,7 @@ typedef struct {
unsigned
int
DirPort_set
:
1
;
unsigned
int
DNSPort_set
:
1
;
unsigned
int
ExtORPort_set
:
1
;
unsigned
int
HTTPTunnelPort_set
:
1
;
/**@}*/
int
AssumeReachable
;
/**< Whether to publish our descriptor regardless. */
...
...
src/or/reasons.c
View file @
4b30ae15
...
...
@@ -45,6 +45,8 @@ stream_end_reason_to_control_string(int reason)
case
END_STREAM_REASON_CANT_ATTACH
:
return
"CANT_ATTACH"
;
case
END_STREAM_REASON_NET_UNREACHABLE
:
return
"NET_UNREACHABLE"
;
case
END_STREAM_REASON_SOCKSPROTOCOL
:
return
"SOCKS_PROTOCOL"
;
// XXXX Controlspec
case
END_STREAM_REASON_HTTPPROTOCOL
:
return
"HTTP_PROTOCOL"
;
case
END_STREAM_REASON_PRIVATE_ADDR
:
return
"PRIVATE_ADDR"
;
...
...
@@ -138,6 +140,11 @@ stream_end_reason_to_socks5_response(int reason)
return
SOCKS5_NET_UNREACHABLE
;
case
END_STREAM_REASON_SOCKSPROTOCOL
:
return
SOCKS5_GENERAL_ERROR
;
case
END_STREAM_REASON_HTTPPROTOCOL
:
// LCOV_EXCL_START
tor_assert_nonfatal_unreached
();
return
SOCKS5_GENERAL_ERROR
;
// LCOV_EXCL_STOP
case
END_STREAM_REASON_PRIVATE_ADDR
:
return
SOCKS5_GENERAL_ERROR
;
...
...
@@ -442,3 +449,48 @@ bandwidth_weight_rule_to_string(bandwidth_weight_rule_t rule)
}
}
/** Given a RELAY_END reason value, convert it to an HTTP response to be
* send over an HTTP tunnel connection. */
const
char
*
end_reason_to_http_connect_response_line
(
int
endreason
)
{
endreason
&=
END_STREAM_REASON_MASK
;
/* XXXX these are probably all wrong. Should they all be 502? */
switch
(
endreason
)
{
case
0
:
return
"HTTP/1.0 200 OK
\r\n\r\n
"
;
case
END_STREAM_REASON_MISC
:
return
"HTTP/1.0 500 Internal Server Error
\r\n\r\n
"
;
case
END_STREAM_REASON_RESOLVEFAILED
:
return
"HTTP/1.0 404 Not Found (resolve failed)
\r\n\r\n
"
;
case
END_STREAM_REASON_NOROUTE
:
return
"HTTP/1.0 404 Not Found (no route)
\r\n\r\n
"
;
case
END_STREAM_REASON_CONNECTREFUSED
:
return
"HTTP/1.0 403 Forbidden (connection refused)
\r\n\r\n
"
;
case
END_STREAM_REASON_EXITPOLICY
:
return
"HTTP/1.0 403 Forbidden (exit policy)
\r\n\r\n
"
;
case
END_STREAM_REASON_DESTROY
:
return
"HTTP/1.0 502 Bad Gateway (destroy cell received)
\r\n\r\n
"
;
case
END_STREAM_REASON_DONE
:
return
"HTTP/1.0 502 Bad Gateway (unexpected close)
\r\n\r\n
"
;
case
END_STREAM_REASON_TIMEOUT
:
return
"HTTP/1.0 504 Gateway Timeout
\r\n\r\n
"
;
case
END_STREAM_REASON_HIBERNATING
:
return
"HTTP/1.0 502 Bad Gateway (hibernating server)
\r\n\r\n
"
;
case
END_STREAM_REASON_INTERNAL
:
return
"HTTP/1.0 502 Bad Gateway (internal error)
\r\n\r\n
"
;
case
END_STREAM_REASON_RESOURCELIMIT
:
return
"HTTP/1.0 502 Bad Gateway (resource limit)
\r\n\r\n
"
;
case
END_STREAM_REASON_CONNRESET
:
return
"HTTP/1.0 403 Forbidden (connection reset)
\r\n\r\n
"
;
case
END_STREAM_REASON_TORPROTOCOL
:
return
"HTTP/1.0 502 Bad Gateway (tor protocol violation)
\r\n\r\n
"
;
case
END_STREAM_REASON_ENTRYPOLICY
:
return
"HTTP/1.0 403 Forbidden (entry policy violation)
\r\n\r\n
"
;
case
END_STREAM_REASON_NOTDIRECTORY
:
/* Fall Through */
default:
tor_assert_nonfatal_unreached
();
return
"HTTP/1.0 500 Internal Server Error (weird end reason)
\r\n\r\n
"
;
}
}
src/or/reasons.h
View file @
4b30ae15
...
...
@@ -26,6 +26,7 @@ const char *socks4_response_code_to_string(uint8_t code);
const
char
*
socks5_response_code_to_string
(
uint8_t
code
);
const
char
*
bandwidth_weight_rule_to_string
(
enum
bandwidth_weight_rule_t
rule
);
const
char
*
end_reason_to_http_connect_response_line
(
int
endreason
);
#endif
src/or/relay.c
View file @
4b30ae15
...
...
@@ -1467,8 +1467,9 @@ connection_edge_process_relay_cell_not_open(
circuit_log_path
(
LOG_INFO
,
LD_APP
,
TO_ORIGIN_CIRCUIT
(
circ
));
/* don't send a socks reply to transparent conns */
tor_assert
(
entry_conn
->
socks_request
!=
NULL
);
if
(
!
entry_conn
->
socks_request
->
has_finished
)
if
(
!
entry_conn
->
socks_request
->
has_finished
)
{
connection_ap_handshake_socks_reply
(
entry_conn
,
NULL
,
0
,
0
);
}
/* Was it a linked dir conn? If so, a dir request just started to
* fetch something; this could be a bootstrap status milestone. */
...
...
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