| 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 { |
| 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); |