|
@@ -242,6 +242,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) {
|
|
@@ -491,6 +496,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);
|
|
@@ -1182,10 +1188,10 @@ consider_plaintext_ports(entry_connection_t *conn, uint16_t port)
|
|
|
* See connection_ap_handshake_rewrite_and_attach()'s
|
|
|
* documentation for arguments and return value.
|
|
|
*/
|
|
|
-int
|
|
|
-connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
|
|
|
- origin_circuit_t *circ,
|
|
|
- crypt_path_t *cpath)
|
|
|
+MOCK_IMPL(int,
|
|
|
+connection_ap_rewrite_and_attach_if_allowed,(entry_connection_t *conn,
|
|
|
+ origin_circuit_t *circ,
|
|
|
+ crypt_path_t *cpath))
|
|
|
{
|
|
|
const or_options_t *options = get_options();
|
|
|
|
|
@@ -2422,6 +2428,108 @@ connection_ap_process_natd(entry_connection_t *conn)
|
|
|
return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * 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) {
|
|
|
+
|
|
|
+ errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
|
|
|
+ goto err;
|
|
|
+ } else if (http_status == 0) {
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * abuse. */
|
|
|
+ {
|
|
|
+ char *authorization = http_get_header(headers, "Proxy-Authorization: ");
|
|
|
+ if (authorization) {
|
|
|
+ socks->username = authorization;
|
|
|
+ socks->usernamelen = strlen(authorization);
|
|
|
+ }
|
|
|
+ char *isolation = http_get_header(headers, "X-Tor-Stream-Isolation: ");
|
|
|
+ if (isolation) {
|
|
|
+ socks->password = isolation;
|
|
|
+ socks->passwordlen = strlen(isolation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* already in use; return it. Return 0 if can't get a unique stream_id.
|
|
|
*/
|
|
@@ -3045,7 +3153,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);
|
|
|
|