mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 20:33:31 +01:00
add support for CONNECTing through https proxies.
not sure if it works. i don't have an https proxy. svn:r3682
This commit is contained in:
parent
8054f82992
commit
6faaac2706
@ -131,6 +131,7 @@ static config_var_t config_vars[] = {
|
||||
VAR("Group", STRING, Group, NULL),
|
||||
VAR("HashedControlPassword",STRING, HashedControlPassword, NULL),
|
||||
VAR("HttpProxy", STRING, HttpProxy, NULL),
|
||||
VAR("HttpsProxy", STRING, HttpsProxy, NULL),
|
||||
VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
|
||||
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
|
||||
VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
|
||||
@ -1463,6 +1464,17 @@ options_validate(or_options_t *options)
|
||||
}
|
||||
}
|
||||
|
||||
if (options->HttpsProxy) { /* parse it now */
|
||||
if (parse_addr_port(options->HttpsProxy, NULL,
|
||||
&options->HttpsProxyAddr, &options->HttpsProxyPort) < 0) {
|
||||
log(LOG_WARN,"HttpsProxy failed to parse or resolve. Please fix.");
|
||||
result = -1;
|
||||
}
|
||||
if (options->HttpsProxyPort == 0) { /* give it a default */
|
||||
options->HttpsProxyPort = 443;
|
||||
}
|
||||
}
|
||||
|
||||
if (options->HashedControlPassword) {
|
||||
if (decode_hashed_password(NULL, options->HashedControlPassword)<0) {
|
||||
log_fn(LOG_WARN,"Bad HashedControlPassword: wrong length or bad base64");
|
||||
|
@ -47,6 +47,56 @@ int connection_or_reached_eof(connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Read conn's inbuf. If the http response from the proxy is all
|
||||
* here, make sure it's good news, and begin the tls handshake. If
|
||||
* it's bad news, close the connection and return -1. Else return 0
|
||||
* and hope for better luck next time.
|
||||
*/
|
||||
static int
|
||||
connection_or_read_proxy_response(connection_t *conn) {
|
||||
|
||||
char *headers;
|
||||
int status_code;
|
||||
time_t date_header;
|
||||
int compression;
|
||||
|
||||
switch (fetch_from_buf_http(conn->inbuf,
|
||||
&headers, MAX_HEADERS_SIZE,
|
||||
NULL, NULL, 10000)) {
|
||||
case -1: /* overflow */
|
||||
log_fn(LOG_WARN,"Your https proxy sent back an oversized response. Closing.");
|
||||
return -1;
|
||||
case 0:
|
||||
log_fn(LOG_INFO,"https proxy response not all here yet. Waiting.");
|
||||
return 0;
|
||||
/* case 1, fall through */
|
||||
}
|
||||
|
||||
if (parse_http_response(headers, &status_code, &date_header,
|
||||
&compression) < 0) {
|
||||
log_fn(LOG_WARN,"Unparseable headers (connecting to '%s'). Closing.",
|
||||
conn->address);
|
||||
tor_free(headers);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status_code == 200) {
|
||||
log_fn(LOG_INFO,"https connect successful (to '%s')! Launching tls.",
|
||||
conn->address);
|
||||
if (connection_tls_start_handshake(conn, 0) < 0) {
|
||||
/* TLS handshaking error of some kind. */
|
||||
connection_mark_for_close(conn);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* else, bad news on the status code */
|
||||
log_fn(LOG_WARN,"The https proxy sent back a bad status code %d. Closing.",
|
||||
status_code);
|
||||
connection_mark_for_close(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Handle any new bytes that have come in on connection <b>conn</b>.
|
||||
* If conn is in 'open' state, hand it to
|
||||
* connection_or_process_cells_from_inbuf()
|
||||
@ -57,9 +107,14 @@ int connection_or_process_inbuf(connection_t *conn) {
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->type == CONN_TYPE_OR);
|
||||
|
||||
if (conn->state != OR_CONN_STATE_OPEN)
|
||||
return 0; /* don't do anything */
|
||||
switch(conn->state) {
|
||||
case OR_CONN_STATE_PROXY_READING:
|
||||
return connection_or_read_proxy_response(conn);
|
||||
case OR_CONN_STATE_OPEN:
|
||||
return connection_or_process_cells_from_inbuf(conn);
|
||||
default:
|
||||
return 0; /* don't do anything */
|
||||
}
|
||||
}
|
||||
|
||||
/** Connection <b>conn</b> has finished writing and has no bytes left on
|
||||
@ -76,15 +131,22 @@ int connection_or_finished_flushing(connection_t *conn) {
|
||||
|
||||
assert_connection_ok(conn,0);
|
||||
|
||||
if (conn->state != OR_CONN_STATE_OPEN) {
|
||||
log_fn(LOG_WARN,"BUG: called in unexpected state %d",conn->state);
|
||||
switch(conn->state) {
|
||||
case OR_CONN_STATE_PROXY_FLUSHING:
|
||||
log_fn(LOG_DEBUG,"finished sending CONNECT to proxy.");
|
||||
conn->state = OR_CONN_STATE_PROXY_READING;
|
||||
connection_stop_writing(conn);
|
||||
break;
|
||||
case OR_CONN_STATE_OPEN:
|
||||
connection_stop_writing(conn);
|
||||
break;
|
||||
default:
|
||||
log_fn(LOG_WARN,"BUG: called in unexpected state %d.", conn->state);
|
||||
#ifdef TOR_FRAGILE
|
||||
tor_assert(0);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
connection_stop_writing(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -99,6 +161,20 @@ int connection_or_finished_connecting(connection_t *conn)
|
||||
log_fn(LOG_INFO,"OR connect() to router at %s:%u finished.",
|
||||
conn->address,conn->port);
|
||||
|
||||
if (get_options()->HttpsProxy) {
|
||||
char buf[1024];
|
||||
char addrbuf[INET_NTOA_BUF_LEN];
|
||||
struct in_addr in;
|
||||
|
||||
in.s_addr = htonl(conn->addr);
|
||||
tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf));
|
||||
tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
|
||||
addrbuf, conn->port);
|
||||
connection_write_to_buf(buf, strlen(buf), conn);
|
||||
conn->state = OR_CONN_STATE_PROXY_FLUSHING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (connection_tls_start_handshake(conn, 0) < 0) {
|
||||
/* TLS handshaking error of some kind. */
|
||||
connection_mark_for_close(conn);
|
||||
@ -212,10 +288,11 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port,
|
||||
const char *id_digest) {
|
||||
connection_t *conn;
|
||||
routerinfo_t *me;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
tor_assert(id_digest);
|
||||
|
||||
if (server_mode(get_options()) && (me=router_get_my_routerinfo()) &&
|
||||
if (server_mode(options) && (me=router_get_my_routerinfo()) &&
|
||||
!memcmp(me->identity_digest, id_digest,DIGEST_LEN)) {
|
||||
log_fn(LOG_WARN,"Bug: Client asked me to connect to myself! Refusing.");
|
||||
return NULL;
|
||||
@ -238,8 +315,15 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port,
|
||||
conn->state = OR_CONN_STATE_CONNECTING;
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED);
|
||||
|
||||
if (options->HttpsProxy) {
|
||||
/* we shouldn't connect directly. use the https proxy instead. */
|
||||
addr = options->HttpsProxyAddr;
|
||||
port = options->HttpsProxyPort;
|
||||
}
|
||||
|
||||
switch (connection_connect(conn, conn->address, addr, port)) {
|
||||
case -1:
|
||||
if (!options->HttpsProxy)
|
||||
router_mark_as_down(conn->identity_digest);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
|
||||
connection_free(conn);
|
||||
@ -252,13 +336,12 @@ connection_t *connection_or_connect(uint32_t addr, uint16_t port,
|
||||
/* case 1: fall through */
|
||||
}
|
||||
|
||||
if (connection_tls_start_handshake(conn, 0) >= 0)
|
||||
return conn;
|
||||
|
||||
/* failure */
|
||||
connection_mark_for_close(conn);
|
||||
if (connection_or_finished_connecting(conn) < 0) {
|
||||
/* already marked for close */
|
||||
return NULL;
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** Begin the tls handshake with <b>conn</b>. <b>receiving</b> is 0 if
|
||||
* we initiated the connection, else it's 1.
|
||||
|
@ -62,9 +62,6 @@ char rend_publish_string[] = "/tor/rendezvous/publish";
|
||||
char rend_fetch_url[] = "/tor/rendezvous/";
|
||||
#endif
|
||||
|
||||
#define MAX_HEADERS_SIZE 50000
|
||||
#define MAX_BODY_SIZE 500000
|
||||
|
||||
#define ALLOW_DIRECTORY_TIME_SKEW 30*60
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
@ -497,7 +494,7 @@ parse_http_url(char *headers, char **url)
|
||||
* if the value of the header is not recognized.
|
||||
* Otherwise, return -1.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
parse_http_response(const char *headers, int *code, time_t *date,
|
||||
int *compression)
|
||||
{
|
||||
|
21
src/or/or.h
21
src/or/or.h
@ -148,6 +148,10 @@
|
||||
#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1)
|
||||
#define MAX_DIR_SIZE 500000
|
||||
|
||||
/* For http parsing */
|
||||
#define MAX_HEADERS_SIZE 50000
|
||||
#define MAX_BODY_SIZE 500000
|
||||
|
||||
#ifdef TOR_PERF
|
||||
/** How long do we keep DNS cache entries before purging them? */
|
||||
#define MAX_DNS_ENTRY_AGE (150*60)
|
||||
@ -220,11 +224,15 @@ typedef enum {
|
||||
#define _OR_CONN_STATE_MIN 1
|
||||
/** State for a connection to an OR: waiting for connect() to finish. */
|
||||
#define OR_CONN_STATE_CONNECTING 1
|
||||
/** State for a connection to an OR: waiting for proxy command to flush. */
|
||||
#define OR_CONN_STATE_PROXY_FLUSHING 2
|
||||
/** State for a connection to an OR: waiting for proxy response. */
|
||||
#define OR_CONN_STATE_PROXY_READING 3
|
||||
/** State for a connection to an OR: SSL is handshaking, not done yet. */
|
||||
#define OR_CONN_STATE_HANDSHAKING 2
|
||||
#define OR_CONN_STATE_HANDSHAKING 4
|
||||
/** State for a connection to an OR: Ready to send/receive cells. */
|
||||
#define OR_CONN_STATE_OPEN 3
|
||||
#define _OR_CONN_STATE_MAX 3
|
||||
#define OR_CONN_STATE_OPEN 5
|
||||
#define _OR_CONN_STATE_MAX 5
|
||||
|
||||
#define _EXIT_CONN_STATE_MIN 1
|
||||
/** State for an exit connection: waiting for response from dns farm. */
|
||||
@ -991,6 +999,10 @@ typedef struct {
|
||||
uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */
|
||||
uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */
|
||||
|
||||
char *HttpsProxy; /**< hostname[:port] to use as https proxy, if any */
|
||||
uint32_t HttpsProxyAddr; /**< Parsed IPv4 addr for https proxy, if any */
|
||||
uint16_t HttpsProxyPort; /**< Parsed port for https proxy, if any */
|
||||
|
||||
struct config_line_t *DirServers; /**< List of configuration lines
|
||||
* for directory servers. */
|
||||
char *MyFamily; /**< Declared family for this OR. */
|
||||
@ -1360,6 +1372,9 @@ void directory_post_to_dirservers(uint8_t purpose, const char *payload,
|
||||
size_t payload_len);
|
||||
void directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
int retry_if_no_servers);
|
||||
int parse_http_response(const char *headers, int *code, time_t *date,
|
||||
int *compression);
|
||||
|
||||
int connection_dir_reached_eof(connection_t *conn);
|
||||
int connection_dir_process_inbuf(connection_t *conn);
|
||||
int connection_dir_finished_flushing(connection_t *conn);
|
||||
|
Loading…
Reference in New Issue
Block a user