dovecot-2.2: lib-http: http-client: Added support for tunneling ...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Oct 12 11:14:58 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/b9498573f0d0
changeset: 16856:b9498573f0d0
user: Stephan Bosch <stephan at rename-it.nl>
date: Sat Oct 12 11:11:04 2013 +0300
description:
lib-http: http-client: Added support for tunneling SSL conntections through proxy.
diffstat:
src/lib-http/http-client-connection.c | 108 ++++++++++++++++++++++++++++++++-
src/lib-http/http-client-host.c | 9 ++-
src/lib-http/http-client-peer.c | 1 +
src/lib-http/http-client-private.h | 21 +++++-
src/lib-http/http-client-request.c | 31 ++++++++-
src/lib-http/http-client.c | 1 +
src/lib-http/http-client.h | 14 ++++
7 files changed, 172 insertions(+), 13 deletions(-)
diffs (truncated from 361 to 300 lines):
diff -r c3884a6acde6 -r b9498573f0d0 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c Sat Oct 12 11:05:08 2013 +0300
+++ b/src/lib-http/http-client-connection.c Sat Oct 12 11:11:04 2013 +0300
@@ -4,6 +4,7 @@
#include "net.h"
#include "str.h"
#include "hash.h"
+#include "llist.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
@@ -912,7 +913,8 @@
http_client_connection_destroy(&conn->conn);
}
-static void http_client_connection_connect(struct http_client_connection *conn)
+static void
+http_client_connection_connect(struct http_client_connection *conn)
{
unsigned int msecs;
@@ -936,6 +938,94 @@
}
}
+static void
+http_client_connect_tunnel_timeout(struct http_client_connection *conn)
+{
+ http_client_connection_unref(&conn);
+}
+
+// FIXME: put something like this in lib/connection.c
+static void
+_connection_init_from_streams(struct connection_list *list,
+ struct connection *conn, const char *name,
+ struct istream *input, struct ostream *output)
+{
+ i_assert(name != NULL);
+
+ conn->list = list;
+ conn->name = i_strdup(name);
+ conn->fd_in = i_stream_get_fd(input);
+ conn->fd_out = o_stream_get_fd(output);
+
+ i_assert(conn->fd_in >= 0);
+ i_assert(conn->fd_out >= 0);
+ i_assert(conn->io == NULL);
+ i_assert(conn->input == NULL);
+ i_assert(conn->output == NULL);
+ i_assert(conn->to == NULL);
+
+ conn->input = input;
+ i_stream_set_name(conn->input, conn->name);
+
+ conn->output = output;
+ o_stream_set_no_error_handling(conn->output, TRUE);
+ o_stream_set_name(conn->output, conn->name);
+
+ conn->io = io_add(conn->fd_in, IO_READ, *list->v.input, conn);
+
+ DLLIST_PREPEND(&list->connections, conn);
+ list->connections_count++;
+
+ if (list->v.client_connected != NULL)
+ list->v.client_connected(conn, TRUE);
+}
+
+static void
+http_client_connection_tunnel_response(const struct http_response *response,
+ struct http_client_connection *conn)
+{
+ struct http_client_tunnel tunnel;
+ const char *name = http_client_peer_addr2str(&conn->peer->addr);
+
+ if (response->status != 200) {
+ http_client_peer_connection_failure(conn->peer, t_strdup_printf(
+ "tunnel connect(%s) failed: %d %s", name,
+ response->status, response->reason));
+ conn->connect_request = NULL;
+ return;
+ }
+
+ http_client_request_start_tunnel(conn->connect_request, &tunnel);
+ conn->connect_request = NULL;
+
+ _connection_init_from_streams
+ (conn->client->conn_list, &conn->conn, name, tunnel.input, tunnel.output);
+}
+
+static void
+http_client_connection_connect_tunnel(struct http_client_connection *conn,
+ const struct ip_addr *ip, unsigned int port)
+{
+ unsigned int msecs;
+
+ conn->connect_start_timestamp = ioloop_timeval;
+
+ conn->connect_request = http_client_request_connect_ip
+ (conn->client, ip, port, http_client_connection_tunnel_response, conn);
+ http_client_request_set_urgent(conn->connect_request);
+ http_client_request_submit(conn->connect_request);
+
+ /* don't use connection.h timeout because we want this timeout
+ to include also the SSL handshake */
+ msecs = conn->client->set.connect_timeout_msecs;
+ if (msecs == 0)
+ msecs = conn->client->set.request_timeout_msecs;
+ if (msecs > 0) {
+ conn->to_connect =
+ timeout_add(msecs, http_client_connect_tunnel_timeout, conn);
+ }
+}
+
struct http_client_connection *
http_client_connection_create(struct http_client_peer *peer)
{
@@ -951,6 +1041,9 @@
case HTTP_CLIENT_PEER_ADDR_HTTPS:
conn_type = "HTTPS";
break;
+ case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
+ conn_type = "Tunneled HTTPS";
+ break;
case HTTP_CLIENT_PEER_ADDR_RAW:
conn_type = "Raw";
break;
@@ -964,9 +1057,13 @@
if (peer->addr.type != HTTP_CLIENT_PEER_ADDR_RAW)
i_array_init(&conn->request_wait_list, 16);
- connection_init_client_ip
- (peer->client->conn_list, &conn->conn, &addr->ip, addr->port);
- http_client_connection_connect(conn);
+ if (peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL) {
+ http_client_connection_connect_tunnel(conn, &addr->ip, addr->port);
+ } else {
+ connection_init_client_ip
+ (peer->client->conn_list, &conn->conn, &addr->ip, addr->port);
+ http_client_connection_connect(conn);
+ }
array_append(&peer->conns, &conn, 1);
@@ -1000,6 +1097,9 @@
conn->closing = TRUE;
conn->connected = FALSE;
+ if (conn->connect_request != NULL)
+ http_client_request_abort(&conn->connect_request);
+
if (conn->incoming_payload != NULL) {
/* the stream is still accessed by lib-http caller. */
i_stream_remove_destroy_callback(conn->incoming_payload,
diff -r c3884a6acde6 -r b9498573f0d0 src/lib-http/http-client-host.c
--- a/src/lib-http/http-client-host.c Sat Oct 12 11:05:08 2013 +0300
+++ b/src/lib-http/http-client-host.c Sat Oct 12 11:11:04 2013 +0300
@@ -428,9 +428,10 @@
}
struct http_client_host *http_client_host_get
-(struct http_client *client, const char *hostname)
+(struct http_client *client, const struct http_url *host_url)
{
struct http_client_host *host;
+ const char *hostname = host_url->host_name;
host = hash_table_lookup(client->hosts, hostname);
if (host == NULL) {
@@ -445,6 +446,12 @@
hash_table_insert(client->hosts, hostname, host);
DLLIST_PREPEND(&client->hosts_list, host);
+ if (host_url->have_host_ip) {
+ host->ips_count = 1;
+ host->ips = i_new(struct ip_addr, host->ips_count);
+ host->ips[0] = host_url->host_ip;
+ }
+
http_client_host_debug(host, "Host created");
}
return host;
diff -r c3884a6acde6 -r b9498573f0d0 src/lib-http/http-client-peer.c
--- a/src/lib-http/http-client-peer.c Sat Oct 12 11:05:08 2013 +0300
+++ b/src/lib-http/http-client-peer.c Sat Oct 12 11:11:04 2013 +0300
@@ -48,6 +48,7 @@
case HTTP_CLIENT_PEER_ADDR_HTTP:
return net_ip_hash(&peer->ip) + peer->port;
case HTTP_CLIENT_PEER_ADDR_HTTPS:
+ case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
return net_ip_hash(&peer->ip) + peer->port +
(peer->https_name == NULL ? 0 : str_hash(peer->https_name));
}
diff -r c3884a6acde6 -r b9498573f0d0 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h Sat Oct 12 11:05:08 2013 +0300
+++ b/src/lib-http/http-client-private.h Sat Oct 12 11:11:04 2013 +0300
@@ -35,6 +35,7 @@
enum http_client_peer_addr_type {
HTTP_CLIENT_PEER_ADDR_HTTP = 0,
HTTP_CLIENT_PEER_ADDR_HTTPS,
+ HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL,
HTTP_CLIENT_PEER_ADDR_RAW
};
@@ -97,6 +98,7 @@
unsigned int submitted:1;
unsigned int connect_tunnel:1;
unsigned int connect_direct:1;
+ unsigned int ssl_tunnel:1;
};
struct http_client_host_port {
@@ -178,6 +180,7 @@
int connect_errno;
struct timeval connect_start_timestamp;
struct timeval connected_timestamp;
+ struct http_client_request *connect_request;
struct ssl_iostream *ssl_iostream;
struct http_response_parser *http_parser;
@@ -248,7 +251,10 @@
addr->type = HTTP_CLIENT_PEER_ADDR_RAW;
addr->port = (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT);
} else if (host_url->have_ssl) {
- addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS;
+ if (req->ssl_tunnel)
+ addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL;
+ else
+ addr->type = HTTP_CLIENT_PEER_ADDR_HTTPS;
addr->https_name = host_url->host_name;
addr->port = (host_url->have_port ? host_url->port : HTTPS_DEFAULT_PORT);
} else {
@@ -260,13 +266,19 @@
static inline const char *
http_client_connection_label(struct http_client_connection *conn)
{
- return t_strdup_printf("%s [%d]",
- http_client_peer_addr2str(&conn->peer->addr), conn->id);
+ return t_strdup_printf("%s%s [%d]",
+ http_client_peer_addr2str(&conn->peer->addr),
+ (conn->peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL ?
+ " (tunnel)" : ""), conn->id);
}
static inline const char *
http_client_peer_label(struct http_client_peer *peer)
{
+ if (peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL) {
+ return t_strconcat
+ (http_client_peer_addr2str(&peer->addr), " (tunnel)", NULL);
+ }
return http_client_peer_addr2str(&peer->addr);
}
@@ -344,7 +356,8 @@
void http_client_peer_switch_ioloop(struct http_client_peer *peer);
struct http_client_host *
- http_client_host_get(struct http_client *client, const char *hostname);
+http_client_host_get(struct http_client *client,
+ const struct http_url *host_url);
void http_client_host_free(struct http_client_host **_host);
void http_client_host_submit_request(struct http_client_host *host,
struct http_client_request *req);
diff -r c3884a6acde6 -r b9498573f0d0 src/lib-http/http-client-request.c
--- a/src/lib-http/http-client-request.c Sat Oct 12 11:05:08 2013 +0300
+++ b/src/lib-http/http-client-request.c Sat Oct 12 11:11:04 2013 +0300
@@ -115,7 +115,24 @@
req->origin_url.port = port;
req->origin_url.have_port = TRUE;
req->connect_tunnel = TRUE;
- req->target = "";
+ req->target = req->origin_url.host_name;
+ return req;
+}
+
+#undef http_client_request_connect_ip
+struct http_client_request *
+http_client_request_connect_ip(struct http_client *client,
+ const struct ip_addr *ip, in_port_t port,
+ http_client_request_callback_t *callback,
+ void *context)
+{
+ struct http_client_request *req;
+ const char *hostname = net_ip2addr(ip);
+
+ req = http_client_request_connect
+ (client, hostname, port, callback, context);
+ req->origin_url.host_ip = *ip;
+ req->origin_url.have_host_ip = TRUE;
return req;
}
@@ -300,9 +317,15 @@
/* determine what host to contact to submit this request */
if (proxy_url != NULL) {
- req->host_url = proxy_url; /* proxy server */
+ if (req->origin_url.have_ssl && !client->set.no_ssl_tunnel &&
+ !req->connect_tunnel) {
+ req->host_url = &req->origin_url; /* tunnel to origin server */
More information about the dovecot-cvs
mailing list