Index: irc.c
===================================================================
--- irc.c	(revision c39cd8e3c06e76359db9ae37b50aac877ff25ce3)
+++ irc.c	(revision df67b487efca9e1a4c43f57375648eb690bcb53d)
@@ -41,7 +41,4 @@
 {
 	irc_t *irc;
-	struct sockaddr_storage sock;
-	socklen_t socklen = sizeof(sock);
-	char *host = NULL, *myhost = NULL;
 	irc_user_t *iu;
 	GSList *l;
@@ -64,21 +61,4 @@
 	irc->iconv = (GIConv) - 1;
 	irc->oconv = (GIConv) - 1;
-
-	if (global.conf->hostname) {
-		myhost = g_strdup(global.conf->hostname);
-	} else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
-		myhost = reverse_lookup((struct sockaddr*) &sock, socklen);
-	}
-
-	if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
-		host = reverse_lookup((struct sockaddr*) &sock, socklen);
-	}
-
-	if (host == NULL) {
-		host = g_strdup("localhost.localdomain");
-	}
-	if (myhost == NULL) {
-		myhost = g_strdup("localhost.localdomain");
-	}
 
 	if (global.conf->ping_interval > 0 && global.conf->ping_timeout > 0) {
@@ -128,15 +108,14 @@
 
 	irc->root = iu = irc_user_new(irc, ROOT_NICK);
-	iu->host = g_strdup(myhost);
 	iu->fullname = g_strdup(ROOT_FN);
 	iu->f = &irc_user_root_funcs;
 
 	iu = irc_user_new(irc, NS_NICK);
-	iu->host = g_strdup(myhost);
 	iu->fullname = g_strdup(ROOT_FN);
 	iu->f = &irc_user_root_funcs;
 
 	irc->user = g_new0(irc_user_t, 1);
-	irc->user->host = g_strdup(host);
+	
+	irc_set_hosts(irc, NULL, 0);
 
 	conf_loaddefaults(irc);
@@ -154,7 +133,4 @@
 	}
 
-	g_free(myhost);
-	g_free(host);
-
 	/* libpurple doesn't like fork()s after initializing itself, so this
 	   is the right moment to initialize it. */
@@ -176,4 +152,50 @@
 
 	return irc;
+}
+
+void irc_set_hosts(irc_t *irc, const struct sockaddr *remote_addr, const socklen_t remote_addrlen)
+{
+	struct sockaddr_storage sock;
+	socklen_t socklen = sizeof(sock);
+	char *host = NULL, *myhost = NULL;
+	struct irc_user *iu;
+
+	if (global.conf->hostname) {
+		myhost = g_strdup(global.conf->hostname);
+	} else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
+		myhost = reverse_lookup((struct sockaddr*) &sock, socklen);
+	}
+
+	if (remote_addrlen > 0) {
+		host = reverse_lookup(remote_addr, remote_addrlen);
+	} else if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
+		host = reverse_lookup((struct sockaddr*) &sock, socklen);
+	}
+
+	if (myhost == NULL) {
+		myhost = g_strdup("localhost.localdomain");
+	}
+	if (host == NULL) {
+		host = g_strdup("localhost.localdomain");
+	}
+	
+	if (irc->root->host != irc->root->nick) {
+		g_free(irc->root->host);
+	}
+	irc->root->host = g_strdup(myhost);
+	if ((iu = irc_user_by_name(irc, NS_NICK))) {
+		if (iu->host != iu->nick) {
+			g_free(iu->host);
+		}
+		iu->host = g_strdup(myhost);
+	}
+	
+	if (irc->user->host != irc->user->nick) {
+		g_free(irc->user->host);
+	}
+	irc->user->host = g_strdup(host);
+
+	g_free(myhost);
+	g_free(host);
 }
 
Index: irc.h
===================================================================
--- irc.h	(revision c39cd8e3c06e76359db9ae37b50aac877ff25ce3)
+++ irc.h	(revision df67b487efca9e1a4c43f57375648eb690bcb53d)
@@ -26,4 +26,6 @@
 #ifndef _IRC_H
 #define _IRC_H
+
+#include <sys/socket.h>
 
 #define IRC_MAX_LINE 512
@@ -271,4 +273,5 @@
 
 irc_t *irc_new(int fd);
+void irc_set_hosts(irc_t *irc, const struct sockaddr *remote_addr, const socklen_t remote_addrlen);
 void irc_abort(irc_t *irc, int immed, char *format, ...) G_GNUC_PRINTF(3, 4);
 void irc_free(irc_t *irc);
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision c39cd8e3c06e76359db9ae37b50aac877ff25ce3)
+++ irc_commands.c	(revision df67b487efca9e1a4c43f57375648eb690bcb53d)
@@ -57,4 +57,46 @@
 		irc_check_login(irc);
 	}
+}
+
+/* http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+
+   This isn't actually IRC, it's used by for example stunnel4 to indicate
+   the origin of the secured counterpart of the connection. It'll go wrong
+   with arguments starting with : like for example "::1" but I guess I'm
+   okay with that. */
+static void irc_cmd_proxy(irc_t *irc, char **cmd)
+{
+	struct addrinfo hints, *ai;
+	struct sockaddr_storage sock;
+	socklen_t socklen = sizeof(sock);
+
+	if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) != 0) {
+		return;
+	}
+
+	ipv64_normalise_mapped(&sock, &socklen);
+
+	/* Only accept PROXY "command" on localhost sockets. */
+	if (!((sock.ss_family == AF_INET &&
+	       ntohl(((struct sockaddr_in*)&sock)->sin_addr.s_addr) == INADDR_LOOPBACK) ||
+	      (sock.ss_family == AF_INET6 &&
+	       IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)&sock)->sin6_addr)))) {
+		return;
+	}
+
+	/* And only once. Do this with a pretty dumb regex-match for
+	   now, maybe better to use some sort of flag.. */
+	if (!g_regex_match_simple("^(ip6-)?localhost(.(localdomain.?)?)?$", irc->user->host, 0, 0)) {
+		return;
+	}
+	
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_NUMERICHOST;
+	if (getaddrinfo(cmd[2], NULL, &hints, &ai) != 0) {
+		return;
+	}
+	
+	irc_set_hosts(irc, ai->ai_addr, ai->ai_addrlen);
+	freeaddrinfo(ai);
 }
 
@@ -808,4 +850,5 @@
 	{ "cap",         1, irc_cmd_cap,         0 },
 	{ "pass",        1, irc_cmd_pass,        0 },
+	{ "proxy",       5, irc_cmd_proxy,       IRC_CMD_PRE_LOGIN },
 	{ "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
 	{ "nick",        1, irc_cmd_nick,        0 },
