libpurple/proxy.c

changeset 25911
f22097dc8413
parent 25888
d0fdd378a635
parent 25624
62b56bc39896
child 27249
3f5b531ae0b3
equal deleted inserted replaced
25910:d24c4a9d28f2 25911:f22097dc8413
1185 1185
1186 purple_proxy_connect_data_disconnect(connect_data, g_strerror(errno)); 1186 purple_proxy_connect_data_disconnect(connect_data, g_strerror(errno));
1187 } 1187 }
1188 1188
1189 static void 1189 static void
1190 s4_canwrite(gpointer data, gint source, PurpleInputCondition cond) 1190 s4_host_resolved(GSList *hosts, gpointer data, const char *error_message)
1191 { 1191 {
1192 PurpleProxyConnectData *connect_data = data;
1192 unsigned char packet[9]; 1193 unsigned char packet[9];
1193 struct hostent *hp; 1194 struct sockaddr *addr;
1194 PurpleProxyConnectData *connect_data = data; 1195
1195 int error = ETIMEDOUT; 1196 connect_data->query_data = NULL;
1196 int ret; 1197
1197 1198 if (error_message != NULL) {
1198 purple_debug_info("socks4 proxy", "Connected.\n"); 1199 purple_proxy_connect_data_disconnect(connect_data, error_message);
1199 1200 return;
1200 if (connect_data->inpa > 0) 1201 }
1201 { 1202
1202 purple_input_remove(connect_data->inpa); 1203 if (hosts == NULL) {
1203 connect_data->inpa = 0;
1204 }
1205
1206 ret = purple_input_get_error(connect_data->fd, &error);
1207 if ((ret != 0) || (error != 0))
1208 {
1209 if (ret != 0)
1210 error = errno;
1211 purple_proxy_connect_data_disconnect(connect_data, g_strerror(error));
1212 return;
1213 }
1214
1215 /*
1216 * The socks4 spec doesn't include support for doing host name
1217 * lookups by the proxy. Some socks4 servers do this via
1218 * extensions to the protocol. Since we don't know if a
1219 * server supports this, it would need to be implemented
1220 * with an option, or some detection mechanism - in the
1221 * meantime, stick with plain old SOCKS4.
1222 */
1223 /* TODO: Use purple_dnsquery_a() */
1224 hp = gethostbyname(connect_data->host);
1225 if (hp == NULL) {
1226 purple_proxy_connect_data_disconnect_formatted(connect_data, 1204 purple_proxy_connect_data_disconnect_formatted(connect_data,
1227 _("Error resolving %s"), connect_data->host); 1205 _("Error resolving %s"), connect_data->host);
1228 return; 1206 return;
1229 } 1207 }
1230 1208
1231 packet[0] = 4; 1209 /* Discard the length... */
1232 packet[1] = 1; 1210 hosts = g_slist_delete_link(hosts, hosts);
1211 addr = hosts->data;
1212 hosts = g_slist_delete_link(hosts, hosts);
1213
1214 packet[0] = 0x04;
1215 packet[1] = 0x01;
1233 packet[2] = connect_data->port >> 8; 1216 packet[2] = connect_data->port >> 8;
1234 packet[3] = connect_data->port & 0xff; 1217 packet[3] = connect_data->port & 0xff;
1235 packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; 1218 memcpy(packet + 4, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4);
1236 packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; 1219 packet[8] = 0x00;
1237 packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; 1220
1238 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; 1221 g_free(addr);
1239 packet[8] = 0; 1222
1223 /* We could try the other hosts, but hopefully that shouldn't be necessary */
1224 while (hosts != NULL) {
1225 /* Discard the length... */
1226 hosts = g_slist_delete_link(hosts, hosts);
1227 /* Free the address... */
1228 g_free(hosts->data);
1229 hosts = g_slist_delete_link(hosts, hosts);
1230 }
1240 1231
1241 connect_data->write_buffer = g_memdup(packet, sizeof(packet)); 1232 connect_data->write_buffer = g_memdup(packet, sizeof(packet));
1242 connect_data->write_buf_len = sizeof(packet); 1233 connect_data->write_buf_len = sizeof(packet);
1243 connect_data->written_len = 0; 1234 connect_data->written_len = 0;
1244 connect_data->read_cb = s4_canread; 1235 connect_data->read_cb = s4_canread;
1245 1236
1246 connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data); 1237 connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
1247 1238
1248 proxy_do_write(connect_data, connect_data->fd, cond); 1239 proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
1240 }
1241
1242 static void
1243 s4_canwrite(gpointer data, gint source, PurpleInputCondition cond)
1244 {
1245 PurpleProxyConnectData *connect_data = data;
1246 int error = ETIMEDOUT;
1247 int ret;
1248
1249 purple_debug_info("socks4 proxy", "Connected.\n");
1250
1251 if (connect_data->inpa > 0) {
1252 purple_input_remove(connect_data->inpa);
1253 connect_data->inpa = 0;
1254 }
1255
1256 ret = purple_input_get_error(connect_data->fd, &error);
1257 if ((ret != 0) || (error != 0)) {
1258 if (ret != 0)
1259 error = errno;
1260 purple_proxy_connect_data_disconnect(connect_data, g_strerror(error));
1261 return;
1262 }
1263
1264 /*
1265 * The socks4 spec doesn't include support for doing host name lookups by
1266 * the proxy. Many socks4 servers do this via the "socks4a" extension to
1267 * the protocol. There doesn't appear to be a way to detect if a server
1268 * supports this, so we require that the user set a global option.
1269 */
1270 if (purple_prefs_get_bool("/purple/proxy/socks4_remotedns")) {
1271 unsigned char packet[9];
1272 int len;
1273
1274 purple_debug_info("socks4 proxy", "Attempting to use remote DNS.\n");
1275
1276 packet[0] = 0x04;
1277 packet[1] = 0x01;
1278 packet[2] = connect_data->port >> 8;
1279 packet[3] = connect_data->port & 0xff;
1280 packet[4] = 0x00;
1281 packet[5] = 0x00;
1282 packet[6] = 0x00;
1283 packet[7] = 0x01;
1284 packet[8] = 0x00;
1285
1286 len = sizeof(packet) + strlen(connect_data->host) + 1;
1287
1288 connect_data->write_buffer = g_malloc0(len);
1289 memcpy(connect_data->write_buffer, packet, sizeof(packet));
1290 memcpy(connect_data->write_buffer + sizeof(packet), connect_data->host, strlen(connect_data->host));
1291 connect_data->write_buf_len = len;
1292 connect_data->written_len = 0;
1293 connect_data->read_cb = s4_canread;
1294
1295 connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
1296
1297 proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
1298 } else {
1299 connect_data->query_data = purple_dnsquery_a(connect_data->host,
1300 connect_data->port, s4_host_resolved, connect_data);
1301
1302 if (connect_data->query_data == NULL) {
1303 purple_debug_error("proxy", "dns query failed unexpectedly.\n");
1304 purple_proxy_connect_data_destroy(connect_data);
1305 }
1306 }
1249 } 1307 }
1250 1308
1251 static void 1309 static void
1252 proxy_connect_socks4(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen) 1310 proxy_connect_socks4(PurpleProxyConnectData *connect_data, struct sockaddr *addr, socklen_t addrlen)
1253 { 1311 {
1404 1462
1405 static void 1463 static void
1406 s5_sendconnect(gpointer data, int source) 1464 s5_sendconnect(gpointer data, int source)
1407 { 1465 {
1408 PurpleProxyConnectData *connect_data = data; 1466 PurpleProxyConnectData *connect_data = data;
1409 int hlen = strlen(connect_data->host); 1467 size_t hlen = strlen(connect_data->host);
1410 connect_data->write_buf_len = 5 + hlen + 2; 1468 connect_data->write_buf_len = 5 + hlen + 2;
1411 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); 1469 connect_data->write_buffer = g_malloc(connect_data->write_buf_len);
1412 connect_data->written_len = 0; 1470 connect_data->written_len = 0;
1413 1471
1414 connect_data->write_buffer[0] = 0x05; 1472 connect_data->write_buffer[0] = 0x05;
1487 PurpleCipher *cipher; 1545 PurpleCipher *cipher;
1488 PurpleCipherContext *ctx; 1546 PurpleCipherContext *ctx;
1489 int i; 1547 int i;
1490 unsigned char Kxoripad[65]; 1548 unsigned char Kxoripad[65];
1491 unsigned char Kxoropad[65]; 1549 unsigned char Kxoropad[65];
1492 int pwlen; 1550 size_t pwlen;
1493 1551
1494 cipher = purple_ciphers_find_cipher("md5"); 1552 cipher = purple_ciphers_find_cipher("md5");
1495 ctx = purple_cipher_context_new(cipher, NULL); 1553 ctx = purple_cipher_context_new(cipher, NULL);
1496 1554
1497 memset(Kxoripad,0,sizeof(Kxoripad)); 1555 memset(Kxoripad,0,sizeof(Kxoripad));
1785 _("Received invalid data on connection with server.")); 1843 _("Received invalid data on connection with server."));
1786 return; 1844 return;
1787 } 1845 }
1788 1846
1789 if (connect_data->read_buffer[1] == 0x02) { 1847 if (connect_data->read_buffer[1] == 0x02) {
1790 gsize i, j; 1848 size_t i, j;
1791 const char *u, *p; 1849 const char *u, *p;
1792 1850
1793 u = purple_proxy_info_get_username(connect_data->gpi); 1851 u = purple_proxy_info_get_username(connect_data->gpi);
1794 p = purple_proxy_info_get_password(connect_data->gpi); 1852 p = purple_proxy_info_get_password(connect_data->gpi);
1795 1853
1818 1876
1819 proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE); 1877 proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
1820 1878
1821 return; 1879 return;
1822 } else if (connect_data->read_buffer[1] == 0x03) { 1880 } else if (connect_data->read_buffer[1] == 0x03) {
1823 gsize userlen; 1881 size_t userlen;
1824 userlen = strlen(purple_proxy_info_get_username(connect_data->gpi)); 1882 userlen = strlen(purple_proxy_info_get_username(connect_data->gpi));
1825 1883
1826 connect_data->write_buf_len = 7 + userlen; 1884 connect_data->write_buf_len = 7 + userlen;
1827 connect_data->write_buffer = g_malloc(connect_data->write_buf_len); 1885 connect_data->write_buffer = g_malloc(connect_data->write_buf_len);
1828 connect_data->written_len = 0; 1886 connect_data->written_len = 0;
1965 #define INET6_ADDRSTRLEN 46 2023 #define INET6_ADDRSTRLEN 46
1966 #endif 2024 #endif
1967 2025
1968 static void try_connect(PurpleProxyConnectData *connect_data) 2026 static void try_connect(PurpleProxyConnectData *connect_data)
1969 { 2027 {
1970 size_t addrlen; 2028 socklen_t addrlen;
1971 struct sockaddr *addr; 2029 struct sockaddr *addr;
1972 char ipaddr[INET6_ADDRSTRLEN]; 2030 char ipaddr[INET6_ADDRSTRLEN];
1973 2031
1974 addrlen = GPOINTER_TO_INT(connect_data->hosts->data); 2032 addrlen = GPOINTER_TO_INT(connect_data->hosts->data);
1975 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); 2033 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
1977 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data); 2035 connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
1978 #ifdef HAVE_INET_NTOP 2036 #ifdef HAVE_INET_NTOP
1979 inet_ntop(addr->sa_family, &((struct sockaddr_in *)addr)->sin_addr, 2037 inet_ntop(addr->sa_family, &((struct sockaddr_in *)addr)->sin_addr,
1980 ipaddr, sizeof(ipaddr)); 2038 ipaddr, sizeof(ipaddr));
1981 #else 2039 #else
1982 memcpy(ipaddr,inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), 2040 memcpy(ipaddr, inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
1983 sizeof(ipaddr)); 2041 sizeof(ipaddr));
1984 #endif 2042 #endif
1985 purple_debug_info("proxy", "Attempting connection to %s\n", ipaddr); 2043 purple_debug_info("proxy", "Attempting connection to %s\n", ipaddr);
1986 2044
1987 switch (purple_proxy_info_get_type(connect_data->gpi)) { 2045 switch (purple_proxy_info_get_type(connect_data->gpi)) {
2301 purple_prefs_add_string("/purple/proxy/type", "none"); 2359 purple_prefs_add_string("/purple/proxy/type", "none");
2302 purple_prefs_add_string("/purple/proxy/host", ""); 2360 purple_prefs_add_string("/purple/proxy/host", "");
2303 purple_prefs_add_int("/purple/proxy/port", 0); 2361 purple_prefs_add_int("/purple/proxy/port", 0);
2304 purple_prefs_add_string("/purple/proxy/username", ""); 2362 purple_prefs_add_string("/purple/proxy/username", "");
2305 purple_prefs_add_string("/purple/proxy/password", ""); 2363 purple_prefs_add_string("/purple/proxy/password", "");
2364 purple_prefs_add_bool("/purple/proxy/socks4_remotedns", FALSE);
2306 2365
2307 /* Setup callbacks for the preferences. */ 2366 /* Setup callbacks for the preferences. */
2308 handle = purple_proxy_get_handle(); 2367 handle = purple_proxy_get_handle();
2309 purple_prefs_connect_callback(handle, "/purple/proxy/type", proxy_pref_cb, 2368 purple_prefs_connect_callback(handle, "/purple/proxy/type", proxy_pref_cb,
2310 NULL); 2369 NULL);

mercurial