changeset 10616:23956a9b915b HEAD

login: Proxying supports now doing DNS lookups for host names.
author Timo Sirainen <tss@iki.fi>
date Sun, 31 Jan 2010 19:11:21 +0200
parents 8f9fc7fa7c73
children 8dcfb629a060
files src/login-common/Makefile.am src/login-common/client-common-auth.c src/login-common/login-proxy.c src/login-common/login-proxy.h
diffstat 4 files changed, 93 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/login-common/Makefile.am	Sun Jan 31 19:10:38 2010 +0200
+++ b/src/login-common/Makefile.am	Sun Jan 31 19:11:21 2010 +0200
@@ -4,6 +4,7 @@
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-auth \
+	-I$(top_srcdir)/src/lib-dns \
 	-I$(top_srcdir)/src/lib-master \
 	-DPKG_STATEDIR=\""$(statedir)"\"
 
--- a/src/login-common/client-common-auth.c	Sun Jan 31 19:10:38 2010 +0200
+++ b/src/login-common/client-common-auth.c	Sun Jan 31 19:11:21 2010 +0200
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 
 #define PROXY_FAILURE_MSG "Account is temporarily unavailable."
+#define LOGIN_DNS_CLIENT_SOCKET_PATH "dns-client"
 
 /* If we've been waiting auth server to respond for over this many milliseconds,
    send a "waiting" message. */
@@ -255,11 +256,11 @@
 	memset(&proxy_set, 0, sizeof(proxy_set));
 	proxy_set.host = reply->host;
 	proxy_set.port = reply->port;
+	proxy_set.dns_client_socket_path = LOGIN_DNS_CLIENT_SOCKET_PATH;
 	proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
 	proxy_set.ssl_flags = reply->ssl_flags;
 
-	if (login_proxy_new(client, &proxy_set, proxy_input,
-			    &client->login_proxy) < 0) {
+	if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
 		client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
 				 PROXY_FAILURE_MSG);
 		return -1;
--- a/src/login-common/login-proxy.c	Sun Jan 31 19:10:38 2010 +0200
+++ b/src/login-common/login-proxy.c	Sun Jan 31 19:11:21 2010 +0200
@@ -8,6 +8,7 @@
 #include "str-sanitize.h"
 #include "time-util.h"
 #include "master-service.h"
+#include "dns-lookup.h"
 #include "client-common.h"
 #include "ssl-proxy.h"
 #include "login-proxy-state.h"
@@ -16,6 +17,7 @@
 #define MAX_PROXY_INPUT_SIZE 4096
 #define OUTBUF_THRESHOLD 1024
 #define LOGIN_PROXY_DIE_IDLE_SECS 2
+#define LOGIN_PROXY_DNS_WARN_MSECS 500
 
 struct login_proxy {
 	struct login_proxy *prev, *next;
@@ -32,8 +34,10 @@
 	struct timeout *to;
 	struct login_proxy_record *state_rec;
 
-	char *host, *user;
+	struct ip_addr ip;
+	char *host;
 	unsigned int port;
+	unsigned int connect_timeout_msecs;
 	enum login_proxy_ssl_flags ssl_flags;
 
 	proxy_callback_t *callback;
@@ -189,63 +193,97 @@
 	login_proxy_free(&proxy);
 }
 
+static int login_proxy_connect(struct login_proxy *proxy)
+{
+	struct login_proxy_record *rec;
+
+	rec = login_proxy_state_get(proxy_state, &proxy->ip, proxy->port);
+	if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
+	    rec->num_waiting_connections != 0) {
+		/* the server is down. fail immediately */
+		login_proxy_free(&proxy);
+		return -1;
+	}
+
+	proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, NULL);
+	if (proxy->server_fd == -1) {
+		i_error("proxy(%s): connect(%s, %u) failed: %m",
+			proxy->client->virtual_user, proxy->host, proxy->port);
+		login_proxy_free(&proxy);
+		return -1;
+	}
+	proxy->server_io = io_add(proxy->server_fd, IO_WRITE,
+				  proxy_wait_connect, proxy);
+	if (proxy->connect_timeout_msecs != 0) {
+		proxy->to = timeout_add(proxy->connect_timeout_msecs,
+					proxy_connect_timeout, proxy);
+	}
+
+	proxy->state_rec = rec;
+	proxy->state_rec->num_waiting_connections++;
+	return 0;
+}
+
+static void login_proxy_dns_done(const struct dns_lookup_result *result,
+				 struct login_proxy *proxy)
+{
+	if (result->ret != 0) {
+		i_error("proxy(%s): DNS lookup of %s failed: %s",
+			proxy->client->virtual_user, proxy->host,
+			result->error);
+		login_proxy_free(&proxy);
+	} else {
+		if (result->msecs > LOGIN_PROXY_DNS_WARN_MSECS) {
+			i_warning("proxy(%s): DNS lookup for %s took %u.%03u s",
+				  proxy->client->virtual_user, proxy->host,
+				  result->msecs/1000, result->msecs % 1000);
+		}
+
+		proxy->ip = result->ips[0];
+		(void)login_proxy_connect(proxy);
+	}
+}
+
 int login_proxy_new(struct client *client,
 		    const struct login_proxy_settings *set,
-		    proxy_callback_t *callback, struct login_proxy **proxy_r)
+		    proxy_callback_t *callback)
 {
 	struct login_proxy *proxy;
-	struct login_proxy_record *rec;
-	struct ip_addr ip;
-	int fd;
+	struct dns_lookup_settings dns_lookup_set;
 
-	if (set->host == NULL) {
+	i_assert(client->login_proxy == NULL);
+
+	if (set->host == NULL || *set->host == '\0') {
 		i_error("proxy(%s): host not given", client->virtual_user);
 		return -1;
 	}
 
-	if (net_addr2ip(set->host, &ip) < 0) {
-		i_error("proxy(%s): %s is not a valid IP",
-			client->virtual_user, set->host);
-		return -1;
-	}
+	proxy = i_new(struct login_proxy, 1);
+	proxy->client = client;
+	proxy->client_fd = -1;
+	proxy->server_fd = -1;
+	proxy->created = ioloop_timeval;
+	proxy->host = i_strdup(set->host);
+	proxy->port = set->port;
+	proxy->connect_timeout_msecs = set->connect_timeout_msecs;
+	proxy->ssl_flags = set->ssl_flags;
+	client_ref(client);
 
-	rec = login_proxy_state_get(proxy_state, &ip, set->port);
-	if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
-	    rec->num_waiting_connections != 0) {
-		/* the server is down. fail immediately */
-	       return -1;
-	}
+	memset(&dns_lookup_set, 0, sizeof(dns_lookup_set));
+	dns_lookup_set.dns_client_socket_path = set->dns_client_socket_path;
+	dns_lookup_set.timeout_msecs = set->connect_timeout_msecs;
 
-	fd = net_connect_ip(&ip, set->port, NULL);
-	if (fd < 0) {
-		i_error("proxy(%s): connect(%s, %u) failed: %m",
-			client->virtual_user, set->host, set->port);
-		return -1;
+	if (net_addr2ip(set->host, &proxy->ip) < 0) {
+		if (dns_lookup(set->host, &dns_lookup_set,
+			       login_proxy_dns_done, proxy) < 0)
+			return -1;
+	} else {
+		if (login_proxy_connect(proxy) < 0)
+			return -1;
 	}
 
-	proxy = i_new(struct login_proxy, 1);
-	proxy->created = ioloop_timeval;
-	proxy->host = i_strdup(set->host);
-	proxy->user = i_strdup(client->virtual_user);
-	proxy->port = set->port;
-	proxy->ssl_flags = set->ssl_flags;
-	proxy->client = client;
-	client_ref(client);
-
-	proxy->server_fd = fd;
-	proxy->server_io = io_add(fd, IO_WRITE, proxy_wait_connect, proxy);
-	if (set->connect_timeout_msecs != 0) {
-		proxy->to = timeout_add(set->connect_timeout_msecs,
-					proxy_connect_timeout, proxy);
-	}
 	proxy->callback = callback;
-
-	proxy->client_fd = -1;
-
-	proxy->state_rec = rec;
-	rec->num_waiting_connections++;
-
-	*proxy_r = proxy;
+	client->login_proxy = proxy;
 	return 0;
 }
 
@@ -282,7 +320,7 @@
 
 		ipstr = net_ip2addr(&proxy->client->ip);
 		i_info("proxy(%s): disconnecting %s",
-		       str_sanitize(proxy->user, 80),
+		       proxy->client->virtual_user,
 		       ipstr != NULL ? ipstr : "");
 
 		if (proxy->client_io != NULL)
@@ -294,15 +332,16 @@
 		i_assert(proxy->client_io == NULL);
 		i_assert(proxy->client_output == NULL);
 
-		proxy->callback(proxy->client);
+		if (proxy->callback != NULL)
+			proxy->callback(proxy->client);
 	}
 
-	net_disconnect(proxy->server_fd);
+	if (proxy->server_fd != -1)
+		net_disconnect(proxy->server_fd);
 
 	if (proxy->ssl_server_proxy != NULL)
 		ssl_proxy_free(&proxy->ssl_server_proxy);
 	i_free(proxy->host);
-	i_free(proxy->user);
 	i_free(proxy);
 
 	client->login_proxy = NULL;
--- a/src/login-common/login-proxy.h	Sun Jan 31 19:10:38 2010 +0200
+++ b/src/login-common/login-proxy.h	Sun Jan 31 19:11:21 2010 +0200
@@ -15,6 +15,7 @@
 
 struct login_proxy_settings {
 	const char *host;
+	const char *dns_client_socket_path;
 	unsigned int port;
 	unsigned int connect_timeout_msecs;
 	enum login_proxy_ssl_flags ssl_flags;
@@ -27,7 +28,7 @@
    called when new input is available from proxy. */
 int login_proxy_new(struct client *client,
 		    const struct login_proxy_settings *set,
-		    proxy_callback_t *callback, struct login_proxy **proxy_r);
+		    proxy_callback_t *callback);
 /* Free the proxy. This should be called if authentication fails. */
 void login_proxy_free(struct login_proxy **proxy);