changeset 25114:e859785b49d8

Implement support for resolving DNS via the SOCKS4 proxy in use. Currently this relies on a global preference, which I'm not super happy about. Ideally, we'd just try to always do this and fall back to a local DNS lookup when the SOCKS4 server doesn't like it, but I don't think we can reliably detect that. Fixes #3230
author Daniel Atallah <daniel.atallah@gmail.com>
date Tue, 17 Feb 2009 23:42:49 +0000
parents 8fa011906ac3
children 163f103347f7 463d8501e4e0
files ChangeLog libpurple/proxy.c pidgin/gtkprefs.c
diffstat 3 files changed, 48 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Feb 17 22:46:20 2009 +0000
+++ b/ChangeLog	Tue Feb 17 23:42:49 2009 +0000
@@ -9,6 +9,7 @@
 	* Fix a memory leak in SILC. (Luke Petre)
 	* Fix some string handling in the SIMPLE prpl, which fixes some buddy name
 	  handling and other issues. (Paul Aurich, Marcus Sundberg)
+	* Implement support for resolving DNS via the SOCKS4 proxy (SOCKS4a).
 
 	ICQ:
 	* Fix retrieval of status messages from users of ICQ 6.x, Miranda, and
--- a/libpurple/proxy.c	Tue Feb 17 22:46:20 2009 +0000
+++ b/libpurple/proxy.c	Tue Feb 17 23:42:49 2009 +0000
@@ -1201,12 +1201,12 @@
 	addr = hosts->data;
 	hosts = g_slist_delete_link(hosts, hosts);
 
-	packet[0] = 4;
-	packet[1] = 1;
+	packet[0] = 0x04;
+	packet[1] = 0x01;
 	packet[2] = connect_data->port >> 8;
 	packet[3] = connect_data->port & 0xff;
 	memcpy(packet + 4, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4);
-	packet[8] = 0;
+	packet[8] = 0x00;
 
 	g_free(addr);
 
@@ -1252,19 +1252,47 @@
 	}
 
 	/*
-	 * The socks4 spec doesn't include support for doing host name
-	 * lookups by the proxy.  Some socks4 servers do this via
-	 * extensions to the protocol.  Since we don't know if a
-	 * server supports this, it would need to be implemented
-	 * with an option, or some detection mechanism - in the
-	 * meantime, stick with plain old SOCKS4.
+	 * The socks4 spec doesn't include support for doing host name lookups by
+	 * the proxy.  Many socks4 servers do this via the "socks4a" extension to
+	 * the protocol.  There doesn't appear to be a way to detect if a server
+	 * supports this, so we require that the user set a global option.
 	 */
-	connect_data->query_data = purple_dnsquery_a(connect_data->host,
-			connect_data->port, s4_host_resolved, connect_data);
+	if (purple_prefs_get_bool("/purple/proxy/socks4_remotedns")) {
+		unsigned char packet[9];
+		int len;
+
+		purple_debug_info("socks4 proxy", "Attempting to use remote DNS.\n");
+
+		packet[0] = 0x04;
+		packet[1] = 0x01;
+		packet[2] = connect_data->port >> 8;
+		packet[3] = connect_data->port & 0xff;
+		packet[4] = 0x00;
+		packet[5] = 0x00;
+		packet[6] = 0x00;
+		packet[7] = 0x01;
+		packet[8] = 0x00;
+
+		len = sizeof(packet) + strlen(connect_data->host) + 1;
 
-	if (connect_data->query_data == NULL) {
-		purple_debug_error("proxy", "dns query failed unexpectedly.\n");
-		purple_proxy_connect_data_destroy(connect_data);
+		connect_data->write_buffer = g_malloc0(len);
+		memcpy(connect_data->write_buffer, packet, sizeof(packet));
+		memcpy(connect_data->write_buffer + sizeof(packet), connect_data->host, strlen(connect_data->host));
+		connect_data->write_buf_len = len;
+		connect_data->written_len = 0;
+		connect_data->read_cb = s4_canread;
+
+		connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
+
+		proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
+	} else {
+		connect_data->query_data = purple_dnsquery_a(connect_data->host,
+				connect_data->port, s4_host_resolved, connect_data);
+
+		if (connect_data->query_data == NULL) {
+			purple_debug_error("proxy", "dns query failed unexpectedly.\n");
+			purple_proxy_connect_data_destroy(connect_data);
+		}
 	}
 }
 
@@ -2323,6 +2351,7 @@
 	purple_prefs_add_int("/purple/proxy/port", 0);
 	purple_prefs_add_string("/purple/proxy/username", "");
 	purple_prefs_add_string("/purple/proxy/password", "");
+	purple_prefs_add_bool("/purple/proxy/socks4_remotedns", FALSE);
 
 	/* Setup callbacks for the preferences. */
 	handle = purple_proxy_get_handle();
--- a/pidgin/gtkprefs.c	Tue Feb 17 22:46:20 2009 +0000
+++ b/pidgin/gtkprefs.c	Tue Feb 17 23:42:49 2009 +0000
@@ -1342,6 +1342,10 @@
 		purple_prefs_connect_callback(prefs, "/purple/proxy/type",
 					    proxy_changed_cb, prefs_proxy_frame);
 
+		/* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */
+		pidgin_prefs_checkbox(_("Use remote DNS with SOCKS4 proxies"),
+							  "/purple/proxy/socks4_remotedns", prefs_proxy_frame);
+
 		table = gtk_table_new(4, 2, FALSE);
 		gtk_container_set_border_width(GTK_CONTAINER(table), 0);
 		gtk_table_set_col_spacings(GTK_TABLE(table), 5);