diff --git a/src/or/config.c b/src/or/config.c index b7e93bc559..a161c980c2 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -133,6 +133,7 @@ static config_var_t config_vars[] = { VAR("Group", STRING, Group, NULL), VAR("HashedControlPassword",STRING, HashedControlPassword, NULL), VAR("HttpProxy", STRING, HttpProxy, NULL), + VAR("HttpProxyAuthenticator",STRING, HttpProxyAuthenticator,NULL), VAR("HttpsProxy", STRING, HttpsProxy, NULL), VAR("HttpsProxyAuthenticator",STRING,HttpsProxyAuthenticator,NULL), VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL), @@ -1527,6 +1528,13 @@ options_validate(or_options_t *options) } } + if (options->HttpProxyAuthenticator) { + if (strlen(options->HttpProxyAuthenticator) >= 48) { + log(LOG_WARN, "HttpProxyAuthenticator is too long (>= 48 chars)."); + result = -1; + } + } + if (options->HttpsProxy) { /* parse it now */ if (parse_addr_port(options->HttpsProxy, NULL, &options->HttpsProxyAddr, &options->HttpsProxyPort) < 0) { diff --git a/src/or/connection.c b/src/or/connection.c index 1b14670a02..7ecff7ba15 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1559,6 +1559,28 @@ int connection_send_destroy(uint16_t circ_id, connection_t *conn) { return 0; } +/** Alloocates a base64'ed authenticator for use in http or https + * auth, based on the input string authenticator. Returns it + * if success, else returns NULL. */ +char * +alloc_http_authenticator(const char *authenticator) { + /* an authenticator in Basic authentication + * is just the string "username:password" */ + const int authenticator_length = strlen(authenticator); + /* The base64_encode function needs a minimum buffer length + * of 66 bytes. */ + const int base64_authenticator_length = (authenticator_length/48+1)*66; + char *base64_authenticator = tor_malloc(base64_authenticator_length); + if (base64_encode(base64_authenticator, base64_authenticator_length, + authenticator, authenticator_length) < 0) { + tor_free(base64_authenticator); /* free and set to null */ + } else { + /* remove extra \n at end of encoding */ + base64_authenticator[strlen(base64_authenticator) - 1] = 0; + } + return base64_authenticator; +} + /** Process new bytes that have arrived on conn-\>inbuf. * * This function just passes conn to the connection-specific diff --git a/src/or/connection_or.c b/src/or/connection_or.c index d83f42c8e8..5aa875d59b 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -169,27 +169,18 @@ int connection_or_finished_connecting(connection_t *conn) char buf[1024]; char addrbuf[INET_NTOA_BUF_LEN]; struct in_addr in; + char *base64_authenticator=NULL; const char *authenticator = get_options()->HttpsProxyAuthenticator; in.s_addr = htonl(conn->addr); tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf)); if (authenticator) { - /* an authenticator in Basic authentication - * is just the string "username:password" */ - const int authenticator_length = strlen(authenticator); - /* The base64_encode function needs a minimum buffer length - * of 66 bytes. */ - const int base64_authenticator_length = (authenticator_length/48+1)*66; - char *base64_authenticator = tor_malloc(base64_authenticator_length); - if (base64_encode(base64_authenticator, base64_authenticator_length, - authenticator, authenticator_length) < 0) { - log_fn(LOG_WARN, "Encoding authenticator failed"); - base64_authenticator[0] = 0; - } else { - /* remove extra \n at end of encoding */ - base64_authenticator[strlen(base64_authenticator) - 1] = 0; - } + base64_authenticator = alloc_http_authenticator(authenticator); + if (!base64_authenticator) + log_fn(LOG_WARN, "Encoding https authenticator failed"); + } + if (base64_authenticator) { tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n" "Proxy-Authorization: Basic %s\r\n\r\n", addrbuf, conn->port, base64_authenticator); diff --git a/src/or/directory.c b/src/or/directory.c index 1ace18ab55..3a4da0c04e 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -363,7 +363,8 @@ directory_send_command(connection_t *conn, const char *platform, int purpose, const char *resource, const char *payload, size_t payload_len) { char tmp[8192]; - char proxystring[128]; + char proxystring[256]; + char proxyauthstring[256]; char hoststring[128]; char url[128]; const char *httpcommand = NULL; @@ -371,15 +372,35 @@ directory_send_command(connection_t *conn, const char *platform, tor_assert(conn); tor_assert(conn->type == CONN_TYPE_DIR); + /* come up with a string for which Host: we want */ if (conn->port == 80) { strlcpy(hoststring, conn->address, sizeof(hoststring)); } else { tor_snprintf(hoststring, sizeof(hoststring),"%s:%d",conn->address, conn->port); } + + /* come up with some proxy lines, if we're using one. */ if (get_options()->HttpProxy) { + char *base64_authenticator=NULL; + const char *authenticator = get_options()->HttpProxyAuthenticator; + tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring); + if (authenticator) { + base64_authenticator = alloc_http_authenticator(authenticator); + if (!base64_authenticator) + log_fn(LOG_WARN, "Encoding http authenticator failed"); + } + if (base64_authenticator) { + tor_snprintf(proxyauthstring, sizeof(proxyauthstring), + "\r\nProxy-Authorization: Basic %s", + base64_authenticator); + tor_free(base64_authenticator); + } else { + proxyauthstring[0] = 0; + } } else { proxystring[0] = 0; + proxyauthstring[0] = 0; } switch (purpose) { @@ -424,12 +445,13 @@ directory_send_command(connection_t *conn, const char *platform, break; } - tor_snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s\r\n\r\n", + tor_snprintf(tmp, sizeof(tmp), "%s %s%s HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n", httpcommand, proxystring, url, payload ? (unsigned long)payload_len : 0, - hoststring); + hoststring, + proxyauthstring); connection_write_to_buf(tmp, strlen(tmp), conn); if (payload) { diff --git a/src/or/or.h b/src/or/or.h index 08282f1d58..6c030a48ec 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1059,11 +1059,12 @@ typedef struct { char *HttpProxy; /**< hostname[:port] to use as http proxy, if any */ uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */ uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */ + char *HttpProxyAuthenticator; /**< username:password string, 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 */ - char *HttpsProxyAuthenticator; /** username:password string, if any */ + char *HttpsProxyAuthenticator; /**< username:password string, if any */ struct config_line_t *DirServers; /**< List of configuration lines * for directory servers. */ @@ -1075,7 +1076,7 @@ typedef struct { smartlist_t *RedirectExitList; /**< List of exit_redirect_t */ int _MonthlyAccountingStart; /**< Deprecated: day of month when accounting * interval starts */ - char *AccountingStart; /** How long is the accounting interval, and when + char *AccountingStart; /**< How long is the accounting interval, and when * does it start? */ uint64_t AccountingMax; /**< How many bytes do we allow per accounting * interval before hibernation? 0 for "never @@ -1317,6 +1318,7 @@ int connection_state_is_open(connection_t *conn); int connection_state_is_connecting(connection_t *conn); int connection_send_destroy(uint16_t circ_id, connection_t *conn); +char *alloc_http_authenticator(const char *authenticator); void assert_connection_ok(connection_t *conn, time_t now); int connection_or_nonopen_was_started_here(connection_t *conn);