Mercurial > pidgin
comparison src/proxy.c @ 9129:3e94a77ee0c7
[gaim-migrate @ 9907]
this will attempt connection to all the hosts that a hostname resolves to,
so if people have ipv6 support, but no ipv6 routes, we can still connect
to servers that have both AAAA and A records. It also makes things a bunch
cleaner, and may fix a bug or two.
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Sun, 30 May 2004 19:30:14 +0000 |
| parents | 4b3e5a5063f9 |
| children | 39155e87c470 |
comparison
equal
deleted
inserted
replaced
| 9128:b5c5c1d13783 | 9129:3e94a77ee0c7 |
|---|---|
| 46 char *host; | 46 char *host; |
| 47 int port; | 47 int port; |
| 48 gint inpa; | 48 gint inpa; |
| 49 GaimProxyInfo *gpi; | 49 GaimProxyInfo *gpi; |
| 50 GaimAccount *account; | 50 GaimAccount *account; |
| 51 GSList *hosts; | |
| 51 }; | 52 }; |
| 53 | |
| 54 static void try_connect(struct PHB *); | |
| 52 | 55 |
| 53 const char* socks5errors[] = { | 56 const char* socks5errors[] = { |
| 54 "succeeded\n", | 57 "succeeded\n", |
| 55 "general SOCKS server failure\n", | 58 "general SOCKS server failure\n", |
| 56 "connection not allowed by ruleset\n", | 59 "connection not allowed by ruleset\n", |
| 240 if(kill(req->dns_pid, 0) != 0) { | 243 if(kill(req->dns_pid, 0) != 0) { |
| 241 gaim_debug(GAIM_DEBUG_WARNING, "dns", | 244 gaim_debug(GAIM_DEBUG_WARNING, "dns", |
| 242 "DNS child %d no longer exists\n", req->dns_pid); | 245 "DNS child %d no longer exists\n", req->dns_pid); |
| 243 return -1; | 246 return -1; |
| 244 } | 247 } |
| 245 | 248 |
| 246 /* Let's contact this lost child! */ | 249 /* Let's contact this lost child! */ |
| 247 rc = write(req->fd_in, dns_params, sizeof(*dns_params)); | 250 rc = write(req->fd_in, dns_params, sizeof(*dns_params)); |
| 248 if(rc<0) { | 251 if(rc<0) { |
| 249 gaim_debug(GAIM_DEBUG_ERROR, "dns", | 252 gaim_debug(GAIM_DEBUG_ERROR, "dns", |
| 250 "Unable to write to DNS child %d: %d\n", | 253 "Unable to write to DNS child %d: %d\n", |
| 251 req->dns_pid, strerror(errno)); | 254 req->dns_pid, strerror(errno)); |
| 252 close(req->fd_in); | 255 close(req->fd_in); |
| 253 return -1; | 256 return -1; |
| 254 } | 257 } |
| 255 | 258 |
| 256 g_return_val_if_fail(rc == sizeof(*dns_params), -1); | 259 g_return_val_if_fail(rc == sizeof(*dns_params), -1); |
| 257 | 260 |
| 258 /* Did you hear me? (This avoids some race conditions) */ | 261 /* Did you hear me? (This avoids some race conditions) */ |
| 259 rc = read(req->fd_out, &ch, 1); | 262 rc = read(req->fd_out, &ch, 1); |
| 260 if(rc != 1 || ch!='Y') { | 263 if(rc != 1 || ch!='Y') { |
| 261 gaim_debug(GAIM_DEBUG_WARNING, "dns", | 264 gaim_debug(GAIM_DEBUG_WARNING, "dns", |
| 262 "DNS child %d not responding. Killing it!\n", | 265 "DNS child %d not responding. Killing it!\n", |
| 366 | 369 |
| 367 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ | 370 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ |
| 368 | 371 |
| 369 req->callback(hosts, req->data, NULL); | 372 req->callback(hosts, req->data, NULL); |
| 370 | 373 |
| 371 while(hosts) { | |
| 372 hosts = g_slist_remove(hosts, hosts->data); | |
| 373 g_free(hosts->data); | |
| 374 hosts = g_slist_remove(hosts, hosts->data); | |
| 375 } | |
| 376 | |
| 377 release_dns_child(req); | 374 release_dns_child(req); |
| 378 } | 375 } |
| 379 | 376 |
| 380 static void trap_gdb_bug() | 377 static void trap_gdb_bug() |
| 381 { | 378 { |
| 422 | 419 |
| 423 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) | 420 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) |
| 424 { | 421 { |
| 425 pending_dns_request_t *req = NULL; | 422 pending_dns_request_t *req = NULL; |
| 426 dns_params_t dns_params; | 423 dns_params_t dns_params; |
| 427 | 424 |
| 428 strncpy(dns_params.hostname, hostname, sizeof(dns_params.hostname)-1); | 425 strncpy(dns_params.hostname, hostname, sizeof(dns_params.hostname)-1); |
| 429 dns_params.hostname[sizeof(dns_params.hostname)-1] = '\0'; | 426 dns_params.hostname[sizeof(dns_params.hostname)-1] = '\0'; |
| 430 dns_params.port = port; | 427 dns_params.port = port; |
| 431 | 428 |
| 432 /* Is there a free available child? */ | 429 /* Is there a free available child? */ |
| 433 while(free_dns_children && !req) { | 430 while(free_dns_children && !req) { |
| 434 GSList *l = free_dns_children; | 431 GSList *l = free_dns_children; |
| 435 free_dns_children = g_slist_remove_link(free_dns_children, l); | 432 free_dns_children = g_slist_remove_link(free_dns_children, l); |
| 436 req = l->data; | 433 req = l->data; |
| 437 g_slist_free(l); | 434 g_slist_free(l); |
| 438 | 435 |
| 439 if(send_dns_request_to_child(req, &dns_params) != 0) { | 436 if(send_dns_request_to_child(req, &dns_params) != 0) { |
| 440 req_free(req); | 437 req_free(req); |
| 441 req = NULL; | 438 req = NULL; |
| 442 continue; | 439 continue; |
| 443 } | 440 } |
| 444 | 441 |
| 445 } | 442 } |
| 446 | 443 |
| 447 if(!req) { | 444 if(!req) { |
| 448 int child_out[2], child_in[2]; | 445 int child_out[2], child_in[2]; |
| 449 | 446 |
| 692 if (ret < 0 || error != 0) { | 689 if (ret < 0 || error != 0) { |
| 693 if(ret!=0) error = errno; | 690 if(ret!=0) error = errno; |
| 694 close(source); | 691 close(source); |
| 695 gaim_input_remove(phb->inpa); | 692 gaim_input_remove(phb->inpa); |
| 696 | 693 |
| 697 if (phb->account == NULL || | |
| 698 gaim_account_get_connection(phb->account) != NULL) { | |
| 699 | |
| 700 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 701 } | |
| 702 | |
| 703 g_free(phb->host); | |
| 704 g_free(phb); | |
| 705 | |
| 706 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 694 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 707 "getsockopt SO_ERROR check: %s\n", strerror(error)); | 695 "getsockopt SO_ERROR check: %s\n", strerror(error)); |
| 696 | |
| 697 try_connect(phb); | |
| 708 return; | 698 return; |
| 709 } | 699 } |
| 710 | 700 |
| 711 fcntl(source, F_SETFL, 0); | 701 fcntl(source, F_SETFL, 0); |
| 712 gaim_input_remove(phb->inpa); | 702 gaim_input_remove(phb->inpa); |
| 791 | 781 |
| 792 static void | 782 static void |
| 793 http_complete(struct PHB *phb, gint source) | 783 http_complete(struct PHB *phb, gint source) |
| 794 { | 784 { |
| 795 gaim_debug(GAIM_DEBUG_INFO, "http proxy", "proxy connection established\n"); | 785 gaim_debug(GAIM_DEBUG_INFO, "http proxy", "proxy connection established\n"); |
| 796 if(!phb->account || phb->account->gc) | 786 if(source < 0) { |
| 787 try_connect(phb); | |
| 788 } else if(!phb->account || phb->account->gc) { | |
| 797 phb->func(phb->data, source, GAIM_INPUT_READ); | 789 phb->func(phb->data, source, GAIM_INPUT_READ); |
| 798 g_free(phb->host); | 790 g_free(phb->host); |
| 799 g_free(phb); | 791 g_free(phb); |
| 792 } | |
| 800 } | 793 } |
| 801 | 794 |
| 802 | 795 |
| 803 /* read the response to the CONNECT request, if we are requesting a non-port-80 tunnel */ | 796 /* read the response to the CONNECT request, if we are requesting a non-port-80 tunnel */ |
| 804 static void | 797 static void |
| 834 status = strtol(p, &p, 10); | 827 status = strtol(p, &p, 10); |
| 835 error = (*p!=' '); | 828 error = (*p!=' '); |
| 836 } | 829 } |
| 837 } | 830 } |
| 838 } | 831 } |
| 839 | 832 |
| 840 if(error) { | 833 if(error) { |
| 841 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 834 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 842 "Unable to parse proxy's response: %s\n", inputline); | 835 "Unable to parse proxy's response: %s\n", inputline); |
| 843 close(source); | 836 close(source); |
| 844 source=-1; | 837 source=-1; |
| 845 } | 838 } |
| 846 else if(status!=200) { | 839 else if(status!=200) { |
| 847 gaim_debug(GAIM_DEBUG_ERROR, "proxy", | 840 gaim_debug(GAIM_DEBUG_ERROR, "proxy", |
| 848 "Proxy server replied with:\n%s\n", p); | 841 "Proxy server replied with:\n%s\n", p); |
| 849 close(source); | 842 close(source); |
| 850 source = -1; | 843 source = -1; |
| 851 | 844 |
| 845 /* XXX: why in the hell are we calling gaim_connection_error() here? */ | |
| 852 if ( status == 403 /* Forbidden */ ) { | 846 if ( status == 403 /* Forbidden */ ) { |
| 853 gchar *msg = g_strdup_printf(_("Access denied: proxy server forbids port %d tunnelling."), phb->port); | 847 gchar *msg = g_strdup_printf(_("Access denied: proxy server forbids port %d tunnelling."), phb->port); |
| 854 gaim_connection_error(phb->account->gc, msg); | 848 gaim_connection_error(phb->account->gc, msg); |
| 855 g_free(msg); | 849 g_free(msg); |
| 856 } else { | 850 } else { |
| 857 char *msg = g_strdup_printf(_("Proxy connection error %d"), status); | 851 char *msg = g_strdup_printf(_("Proxy connection error %d"), status); |
| 858 gaim_connection_error(phb->account->gc, msg); | 852 gaim_connection_error(phb->account->gc, msg); |
| 859 g_free(msg); | 853 g_free(msg); |
| 860 } | 854 } |
| 861 | 855 |
| 862 } else { | 856 } else { |
| 863 http_complete(phb, source); | 857 http_complete(phb, source); |
| 864 } | 858 } |
| 865 | 859 |
| 866 return; | 860 return; |
| 867 } | 861 } |
| 868 | 862 |
| 869 static void | 863 static void |
| 870 http_canwrite(gpointer data, gint source, GaimInputCondition cond) | 864 http_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 883 len = sizeof(error); | 877 len = sizeof(error); |
| 884 | 878 |
| 885 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 879 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 886 close(source); | 880 close(source); |
| 887 | 881 |
| 888 if (phb->account == NULL || | 882 try_connect(phb); |
| 889 gaim_account_get_connection(phb->account) != NULL) { | |
| 890 | |
| 891 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 892 } | |
| 893 | |
| 894 g_free(phb->host); | |
| 895 g_free(phb); | |
| 896 return; | 883 return; |
| 897 } | 884 } |
| 898 | 885 |
| 899 gaim_debug(GAIM_DEBUG_INFO, "proxy", "using CONNECT tunnelling for %s:%d\n", phb->host, phb->port); | 886 gaim_debug(GAIM_DEBUG_INFO, "proxy", "using CONNECT tunnelling for %s:%d\n", phb->host, phb->port); |
| 900 request_len = g_snprintf(request, sizeof(request), | 887 request_len = g_snprintf(request, sizeof(request), |
| 921 request_len += 2; | 908 request_len += 2; |
| 922 | 909 |
| 923 if (write(source, request, request_len) < 0) { | 910 if (write(source, request, request_len) < 0) { |
| 924 close(source); | 911 close(source); |
| 925 | 912 |
| 926 if (phb->account == NULL || | 913 try_connect(phb); |
| 927 gaim_account_get_connection(phb->account) != NULL) { | |
| 928 | |
| 929 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 930 } | |
| 931 | |
| 932 g_free(phb->host); | |
| 933 g_free(phb); | |
| 934 return; | 914 return; |
| 935 } | 915 } |
| 936 | 916 |
| 937 /* register the response handler for the CONNECT request */ | 917 /* register the response handler for the CONNECT request */ |
| 938 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); | 918 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); |
| 1013 return; | 993 return; |
| 1014 } | 994 } |
| 1015 | 995 |
| 1016 close(source); | 996 close(source); |
| 1017 | 997 |
| 1018 if (phb->account == NULL || | 998 try_connect(phb); |
| 1019 gaim_account_get_connection(phb->account) != NULL) { | |
| 1020 | |
| 1021 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1022 } | |
| 1023 | |
| 1024 g_free(phb->host); | |
| 1025 g_free(phb); | |
| 1026 } | 999 } |
| 1027 | 1000 |
| 1028 static void | 1001 static void |
| 1029 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) | 1002 s4_canwrite(gpointer data, gint source, GaimInputCondition cond) |
| 1030 { | 1003 { |
| 1042 len = sizeof(error); | 1015 len = sizeof(error); |
| 1043 | 1016 |
| 1044 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1017 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1045 close(source); | 1018 close(source); |
| 1046 | 1019 |
| 1047 if (phb->account == NULL || | 1020 try_connect(phb); |
| 1048 gaim_account_get_connection(phb->account) != NULL) { | |
| 1049 | |
| 1050 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1051 } | |
| 1052 | |
| 1053 g_free(phb->host); | |
| 1054 g_free(phb); | |
| 1055 return; | 1021 return; |
| 1056 } | 1022 } |
| 1057 fcntl(source, F_SETFL, 0); | 1023 fcntl(source, F_SETFL, 0); |
| 1058 | 1024 |
| 1059 /* XXX does socks4 not support host name lookups by the proxy? */ | 1025 /* XXX does socks4 not support host name lookups by the proxy? */ |
| 1060 if (!(hp = gethostbyname(phb->host))) { | 1026 if (!(hp = gethostbyname(phb->host))) { |
| 1061 close(source); | 1027 close(source); |
| 1062 | 1028 |
| 1063 if (phb->account == NULL || | 1029 try_connect(phb); |
| 1064 gaim_account_get_connection(phb->account) != NULL) { | |
| 1065 | |
| 1066 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1067 } | |
| 1068 | |
| 1069 g_free(phb->host); | |
| 1070 g_free(phb); | |
| 1071 return; | 1030 return; |
| 1072 } | 1031 } |
| 1073 | 1032 |
| 1074 packet[0] = 4; | 1033 packet[0] = 4; |
| 1075 packet[1] = 1; | 1034 packet[1] = 1; |
| 1082 packet[8] = 0; | 1041 packet[8] = 0; |
| 1083 | 1042 |
| 1084 if (write(source, packet, 9) != 9) { | 1043 if (write(source, packet, 9) != 9) { |
| 1085 close(source); | 1044 close(source); |
| 1086 | 1045 |
| 1087 if (phb->account == NULL || | 1046 try_connect(phb); |
| 1088 gaim_account_get_connection(phb->account) != NULL) { | |
| 1089 | |
| 1090 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1091 } | |
| 1092 | |
| 1093 g_free(phb->host); | |
| 1094 g_free(phb); | |
| 1095 return; | 1047 return; |
| 1096 } | 1048 } |
| 1097 | 1049 |
| 1098 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); | 1050 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb); |
| 1099 } | 1051 } |
| 1156 | 1108 |
| 1157 if (read(source, buf, 4) < 4) { | 1109 if (read(source, buf, 4) < 4) { |
| 1158 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n"); | 1110 gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n"); |
| 1159 close(source); | 1111 close(source); |
| 1160 | 1112 |
| 1161 if (phb->account == NULL || | 1113 try_connect(phb); |
| 1162 gaim_account_get_connection(phb->account) != NULL) { | |
| 1163 | |
| 1164 phb->func(phb->data, source, GAIM_INPUT_READ); | |
| 1165 } | |
| 1166 | |
| 1167 g_free(phb->host); | |
| 1168 g_free(phb); | |
| 1169 return; | 1114 return; |
| 1170 } | 1115 } |
| 1171 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { | 1116 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { |
| 1172 if ((buf[0] == 0x05) && (buf[1] < 0x09)) | 1117 if ((buf[0] == 0x05) && (buf[1] < 0x09)) |
| 1173 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", socks5errors[buf[1]]); | 1118 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", socks5errors[buf[1]]); |
| 1174 else | 1119 else |
| 1175 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n"); | 1120 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n"); |
| 1176 close(source); | 1121 close(source); |
| 1177 | 1122 |
| 1178 if (phb->account == NULL || | 1123 try_connect(phb); |
| 1179 gaim_account_get_connection(phb->account) != NULL) { | |
| 1180 | |
| 1181 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1182 } | |
| 1183 | |
| 1184 g_free(phb->host); | |
| 1185 g_free(phb); | |
| 1186 return; | 1124 return; |
| 1187 } | 1125 } |
| 1188 | 1126 |
| 1189 /* Skip past BND.ADDR */ | 1127 /* Skip past BND.ADDR */ |
| 1190 switch(buf[3]) { | 1128 switch(buf[3]) { |
| 1232 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; | 1170 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; |
| 1233 | 1171 |
| 1234 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { | 1172 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { |
| 1235 close(source); | 1173 close(source); |
| 1236 | 1174 |
| 1237 if (phb->account == NULL || | 1175 try_connect(phb); |
| 1238 gaim_account_get_connection(phb->account) != NULL) { | |
| 1239 | |
| 1240 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1241 } | |
| 1242 | |
| 1243 g_free(phb->host); | |
| 1244 g_free(phb); | |
| 1245 return; | 1176 return; |
| 1246 } | 1177 } |
| 1247 | 1178 |
| 1248 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); | 1179 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); |
| 1249 } | 1180 } |
| 1258 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got auth response.\n"); | 1189 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Got auth response.\n"); |
| 1259 | 1190 |
| 1260 if (read(source, buf, 2) < 2) { | 1191 if (read(source, buf, 2) < 2) { |
| 1261 close(source); | 1192 close(source); |
| 1262 | 1193 |
| 1263 if (phb->account == NULL || | 1194 try_connect(phb); |
| 1264 gaim_account_get_connection(phb->account) != NULL) { | |
| 1265 | |
| 1266 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1267 } | |
| 1268 | |
| 1269 g_free(phb->host); | |
| 1270 g_free(phb); | |
| 1271 return; | 1195 return; |
| 1272 } | 1196 } |
| 1273 | 1197 |
| 1274 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { | 1198 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { |
| 1275 close(source); | 1199 close(source); |
| 1276 | 1200 |
| 1277 if (phb->account == NULL || | 1201 try_connect(phb); |
| 1278 gaim_account_get_connection(phb->account) != NULL) { | |
| 1279 | |
| 1280 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1281 } | |
| 1282 | |
| 1283 g_free(phb->host); | |
| 1284 g_free(phb); | |
| 1285 return; | 1202 return; |
| 1286 } | 1203 } |
| 1287 | 1204 |
| 1288 s5_sendconnect(phb, source); | 1205 s5_sendconnect(phb, source); |
| 1289 } | 1206 } |
| 1298 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read.\n"); | 1215 gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read.\n"); |
| 1299 | 1216 |
| 1300 if (read(source, buf, 2) < 2) { | 1217 if (read(source, buf, 2) < 2) { |
| 1301 close(source); | 1218 close(source); |
| 1302 | 1219 |
| 1303 if (phb->account == NULL || | 1220 try_connect(phb); |
| 1304 gaim_account_get_connection(phb->account) != NULL) { | |
| 1305 | |
| 1306 phb->func(phb->data, source, GAIM_INPUT_READ); | |
| 1307 } | |
| 1308 | |
| 1309 g_free(phb->host); | |
| 1310 g_free(phb); | |
| 1311 return; | 1221 return; |
| 1312 } | 1222 } |
| 1313 | 1223 |
| 1314 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { | 1224 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { |
| 1315 close(source); | 1225 close(source); |
| 1316 | 1226 |
| 1317 if (phb->account == NULL || | 1227 try_connect(phb); |
| 1318 gaim_account_get_connection(phb->account) != NULL) { | |
| 1319 | |
| 1320 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1321 } | |
| 1322 | |
| 1323 g_free(phb->host); | |
| 1324 g_free(phb); | |
| 1325 return; | 1228 return; |
| 1326 } | 1229 } |
| 1327 | 1230 |
| 1328 if (buf[1] == 0x02) { | 1231 if (buf[1] == 0x02) { |
| 1329 unsigned int i, j; | 1232 unsigned int i, j; |
| 1330 | 1233 |
| 1331 i = strlen(gaim_proxy_info_get_username(phb->gpi)); | 1234 i = strlen(gaim_proxy_info_get_username(phb->gpi)); |
| 1332 j = strlen(gaim_proxy_info_get_password(phb->gpi)); | 1235 j = strlen(gaim_proxy_info_get_password(phb->gpi)); |
| 1333 | 1236 |
| 1334 buf[0] = 0x01; /* version 1 */ | 1237 buf[0] = 0x01; /* version 1 */ |
| 1335 buf[1] = i; | 1238 buf[1] = i; |
| 1338 memcpy(buf + 2 + i + 1, gaim_proxy_info_get_password(phb->gpi), j); | 1241 memcpy(buf + 2 + i + 1, gaim_proxy_info_get_password(phb->gpi), j); |
| 1339 | 1242 |
| 1340 if (write(source, buf, 3 + i + j) < 3 + i + j) { | 1243 if (write(source, buf, 3 + i + j) < 3 + i + j) { |
| 1341 close(source); | 1244 close(source); |
| 1342 | 1245 |
| 1343 if (phb->account == NULL || | 1246 try_connect(phb); |
| 1344 gaim_account_get_connection(phb->account) != NULL) { | |
| 1345 | |
| 1346 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1347 } | |
| 1348 | |
| 1349 g_free(phb->host); | |
| 1350 g_free(phb); | |
| 1351 return; | 1247 return; |
| 1352 } | 1248 } |
| 1353 | 1249 |
| 1354 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); | 1250 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); |
| 1355 } | 1251 } |
| 1373 gaim_input_remove(phb->inpa); | 1269 gaim_input_remove(phb->inpa); |
| 1374 | 1270 |
| 1375 len = sizeof(error); | 1271 len = sizeof(error); |
| 1376 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1272 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1377 close(source); | 1273 close(source); |
| 1378 if (phb->account == NULL || | 1274 |
| 1379 gaim_account_get_connection(phb->account) != NULL) { | 1275 try_connect(phb); |
| 1380 | |
| 1381 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1382 } | |
| 1383 | |
| 1384 g_free(phb->host); | |
| 1385 g_free(phb); | |
| 1386 return; | 1276 return; |
| 1387 } | 1277 } |
| 1388 fcntl(source, F_SETFL, 0); | 1278 fcntl(source, F_SETFL, 0); |
| 1389 | 1279 |
| 1390 i = 0; | 1280 i = 0; |
| 1404 | 1294 |
| 1405 if (write(source, buf, i) < i) { | 1295 if (write(source, buf, i) < i) { |
| 1406 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n"); | 1296 gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n"); |
| 1407 close(source); | 1297 close(source); |
| 1408 | 1298 |
| 1409 if (phb->account == NULL || | 1299 try_connect(phb); |
| 1410 gaim_account_get_connection(phb->account) != NULL) { | |
| 1411 | |
| 1412 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1413 } | |
| 1414 | |
| 1415 g_free(phb->host); | |
| 1416 g_free(phb); | |
| 1417 return; | 1300 return; |
| 1418 } | 1301 } |
| 1419 | 1302 |
| 1420 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); | 1303 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb); |
| 1421 } | 1304 } |
| 1467 } | 1350 } |
| 1468 | 1351 |
| 1469 return fd; | 1352 return fd; |
| 1470 } | 1353 } |
| 1471 | 1354 |
| 1355 static void try_connect(struct PHB *phb) | |
| 1356 { | |
| 1357 size_t addrlen; | |
| 1358 struct sockaddr *addr; | |
| 1359 int ret = -1; | |
| 1360 | |
| 1361 while (phb->hosts) { | |
| 1362 addrlen = GPOINTER_TO_INT(phb->hosts->data); | |
| 1363 phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data); | |
| 1364 addr = phb->hosts->data; | |
| 1365 phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data); | |
| 1366 | |
| 1367 switch (gaim_proxy_info_get_type(phb->gpi)) { | |
| 1368 case GAIM_PROXY_NONE: | |
| 1369 ret = proxy_connect_none(phb, addr, addrlen); | |
| 1370 break; | |
| 1371 | |
| 1372 case GAIM_PROXY_HTTP: | |
| 1373 ret = proxy_connect_http(phb, addr, addrlen); | |
| 1374 break; | |
| 1375 | |
| 1376 case GAIM_PROXY_SOCKS4: | |
| 1377 ret = proxy_connect_socks4(phb, addr, addrlen); | |
| 1378 break; | |
| 1379 | |
| 1380 case GAIM_PROXY_SOCKS5: | |
| 1381 ret = proxy_connect_socks5(phb, addr, addrlen); | |
| 1382 break; | |
| 1383 | |
| 1384 case GAIM_PROXY_USE_ENVVAR: | |
| 1385 ret = proxy_connect_http(phb, addr, addrlen); | |
| 1386 break; | |
| 1387 | |
| 1388 default: | |
| 1389 break; | |
| 1390 } | |
| 1391 | |
| 1392 g_free(addr); | |
| 1393 | |
| 1394 if (ret > 0) | |
| 1395 break; | |
| 1396 } | |
| 1397 | |
| 1398 if (ret < 0) { | |
| 1399 if (phb->account == NULL || | |
| 1400 gaim_account_get_connection(phb->account) != NULL) { | |
| 1401 | |
| 1402 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1403 } | |
| 1404 | |
| 1405 g_free(phb->host); | |
| 1406 g_free(phb); | |
| 1407 } | |
| 1408 } | |
| 1409 | |
| 1472 static void | 1410 static void |
| 1473 connection_host_resolved(GSList *hosts, gpointer data, | 1411 connection_host_resolved(GSList *hosts, gpointer data, |
| 1474 const char *error_message) | 1412 const char *error_message) |
| 1475 { | 1413 { |
| 1476 struct PHB *phb = (struct PHB*)data; | 1414 struct PHB *phb = (struct PHB*)data; |
| 1477 size_t addrlen; | 1415 |
| 1478 struct sockaddr *addr; | 1416 phb->hosts = hosts; |
| 1479 int ret = -1; | 1417 |
| 1480 | 1418 try_connect(phb); |
| 1481 while (hosts) { | |
| 1482 addrlen = GPOINTER_TO_INT(hosts->data); | |
| 1483 hosts = hosts->next; | |
| 1484 addr = hosts->data; | |
| 1485 hosts = hosts->next; | |
| 1486 | |
| 1487 switch (gaim_proxy_info_get_type(phb->gpi)) | |
| 1488 { | |
| 1489 case GAIM_PROXY_NONE: | |
| 1490 ret = proxy_connect_none(phb, addr, addrlen); | |
| 1491 break; | |
| 1492 | |
| 1493 case GAIM_PROXY_HTTP: | |
| 1494 ret = proxy_connect_http(phb, addr, addrlen); | |
| 1495 break; | |
| 1496 | |
| 1497 case GAIM_PROXY_SOCKS4: | |
| 1498 ret = proxy_connect_socks4(phb, addr, addrlen); | |
| 1499 break; | |
| 1500 | |
| 1501 case GAIM_PROXY_SOCKS5: | |
| 1502 ret = proxy_connect_socks5(phb, addr, addrlen); | |
| 1503 break; | |
| 1504 | |
| 1505 case GAIM_PROXY_USE_ENVVAR: | |
| 1506 ret = proxy_connect_http(phb, addr, addrlen); | |
| 1507 break; | |
| 1508 | |
| 1509 default: | |
| 1510 break; | |
| 1511 } | |
| 1512 | |
| 1513 if (ret > 0) | |
| 1514 break; | |
| 1515 } | |
| 1516 | |
| 1517 if (ret < 0) { | |
| 1518 if (phb->account == NULL || | |
| 1519 gaim_account_get_connection(phb->account) != NULL) { | |
| 1520 | |
| 1521 phb->func(phb->data, -1, GAIM_INPUT_READ); | |
| 1522 } | |
| 1523 | |
| 1524 g_free(phb->host); | |
| 1525 g_free(phb); | |
| 1526 } | |
| 1527 } | 1419 } |
| 1528 | 1420 |
| 1529 int | 1421 int |
| 1530 gaim_proxy_connect(GaimAccount *account, const char *host, int port, | 1422 gaim_proxy_connect(GaimAccount *account, const char *host, int port, |
| 1531 GaimInputFunction func, gpointer data) | 1423 GaimInputFunction func, gpointer data) |
| 1557 (tmp = g_getenv("http_proxy")) != NULL || | 1449 (tmp = g_getenv("http_proxy")) != NULL || |
| 1558 (tmp= g_getenv("HTTPPROXY")) != NULL) { | 1450 (tmp= g_getenv("HTTPPROXY")) != NULL) { |
| 1559 char *proxyhost,*proxypath; | 1451 char *proxyhost,*proxypath; |
| 1560 int proxyport; | 1452 int proxyport; |
| 1561 | 1453 |
| 1562 /* http_proxy-format: | 1454 /* http_proxy-format: |
| 1563 * export http_proxy="http://your.proxy.server:port/" | 1455 * export http_proxy="http://your.proxy.server:port/" |
| 1564 */ | 1456 */ |
| 1565 if(gaim_url_parse(tmp, &proxyhost, &proxyport, &proxypath)) { | 1457 if(gaim_url_parse(tmp, &proxyhost, &proxyport, &proxypath)) { |
| 1566 gaim_proxy_info_set_host(phb->gpi, proxyhost); | 1458 gaim_proxy_info_set_host(phb->gpi, proxyhost); |
| 1567 g_free(proxyhost); | 1459 g_free(proxyhost); |
| 1568 g_free(proxypath); | 1460 g_free(proxypath); |
| 1569 | 1461 |
| 1570 /* only for backward compatibility */ | 1462 /* only for backward compatibility */ |
| 1571 if (proxyport == 80 && | 1463 if (proxyport == 80 && |
| 1572 ((tmp = g_getenv("HTTP_PROXY_PORT")) != NULL || | 1464 ((tmp = g_getenv("HTTP_PROXY_PORT")) != NULL || |
| 1573 (tmp = g_getenv("http_proxy_port")) != NULL || | 1465 (tmp = g_getenv("http_proxy_port")) != NULL || |
| 1574 (tmp = g_getenv("HTTPPROXYPORT")) != NULL)) | 1466 (tmp = g_getenv("HTTPPROXYPORT")) != NULL)) |
| 1575 proxyport = atoi(tmp); | 1467 proxyport = atoi(tmp); |
| 1576 | 1468 |
| 1577 gaim_proxy_info_set_port(phb->gpi, proxyport); | 1469 gaim_proxy_info_set_port(phb->gpi, proxyport); |
| 1578 } | 1470 } |
| 1579 } | 1471 } |
| 1580 | 1472 |
| 1581 if ((tmp = g_getenv("HTTP_PROXY_USER")) != NULL || | 1473 if ((tmp = g_getenv("HTTP_PROXY_USER")) != NULL || |
