diff libpurple/proxy.c @ 25480: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 4b8c4870b13a
line wrap: on
line diff
--- 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();