00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #include <string.h>
00027
00028 #ifdef NEED_MALLOC_H
00029 #include <malloc.h>
00030 #endif
00031 #ifdef HAVE_STDLIB_H
00032 #include <stdlib.h>
00033 #endif
00034 #ifdef HAVE_SYS_SOCKET_H
00035 #include <sys/socket.h>
00036 #endif
00037 #ifdef HAVE_NETINET_IN_H
00038 #include <netinet/in.h>
00039 #endif
00040 #ifdef HAVE_ARPA_INET_H
00041 #include <arpa/inet.h>
00042 #endif
00043
00044 #include "urldata.h"
00045 #include "sendf.h"
00046 #include "strequal.h"
00047 #include "select.h"
00048 #include "connect.h"
00049 #include "timeval.h"
00050 #include "socks.h"
00051
00052
00053 #include "memdebug.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062 static int blockread_all(struct connectdata *conn,
00063 curl_socket_t sockfd,
00064 char *buf,
00065 ssize_t buffersize,
00066 ssize_t *n,
00067 long conn_timeout)
00068
00069
00070 {
00071 ssize_t nread;
00072 ssize_t allread = 0;
00073 int result;
00074 struct timeval tvnow;
00075 long conntime;
00076 *n = 0;
00077 do {
00078 tvnow = Curl_tvnow();
00079
00080 conntime = Curl_tvdiff(tvnow, conn->created);
00081 if(conntime > conn_timeout) {
00082
00083 result = ~CURLE_OK;
00084 break;
00085 }
00086 if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD,
00087 (int)(conn_timeout - conntime)) <= 0) {
00088 result = ~CURLE_OK;
00089 break;
00090 }
00091 result = Curl_read(conn, sockfd, buf, buffersize, &nread);
00092 if(result)
00093 break;
00094
00095 if(buffersize == nread) {
00096 allread += nread;
00097 *n = allread;
00098 result = CURLE_OK;
00099 break;
00100 }
00101 if(!nread) {
00102 result = ~CURLE_OK;
00103 break;
00104 }
00105
00106 buffersize -= nread;
00107 buf += nread;
00108 allread += nread;
00109 } while(1);
00110 return result;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 CURLcode Curl_SOCKS4(const char *proxy_name,
00125 char *hostname,
00126 int remote_port,
00127 int sockindex,
00128 struct connectdata *conn)
00129 {
00130 unsigned char socksreq[262];
00131 int result;
00132 CURLcode code;
00133 curl_socket_t sock = conn->sock[sockindex];
00134 long timeout;
00135 struct SessionHandle *data = conn->data;
00136
00137
00138 if(data->set.timeout && data->set.connecttimeout) {
00139 if (data->set.timeout < data->set.connecttimeout)
00140 timeout = data->set.timeout;
00141 else
00142 timeout = data->set.connecttimeout;
00143 }
00144 else if(data->set.timeout)
00145 timeout = data->set.timeout;
00146 else if(data->set.connecttimeout)
00147 timeout = data->set.connecttimeout;
00148 else
00149 timeout = DEFAULT_CONNECT_TIMEOUT;
00150
00151 Curl_nonblock(sock, FALSE);
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 socksreq[0] = 4;
00165 socksreq[1] = 1;
00166 *((unsigned short*)&socksreq[2]) = htons((unsigned short)remote_port);
00167
00168
00169 {
00170 struct Curl_dns_entry *dns;
00171 Curl_addrinfo *hp=NULL;
00172 int rc;
00173
00174 rc = Curl_resolv(conn, hostname, remote_port, &dns);
00175
00176 if(rc == CURLRESOLV_ERROR)
00177 return CURLE_COULDNT_RESOLVE_PROXY;
00178
00179 if(rc == CURLRESOLV_PENDING)
00180
00181 rc = Curl_wait_for_resolv(conn, &dns);
00182
00183
00184
00185
00186
00187 if(dns)
00188 hp=dns->addr;
00189 if (hp) {
00190 char buf[64];
00191 unsigned short ip[4];
00192 Curl_printable_address(hp, buf, sizeof(buf));
00193
00194 if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
00195 &ip[0], &ip[1], &ip[2], &ip[3])) {
00196
00197 socksreq[4] = (unsigned char)ip[0];
00198 socksreq[5] = (unsigned char)ip[1];
00199 socksreq[6] = (unsigned char)ip[2];
00200 socksreq[7] = (unsigned char)ip[3];
00201 }
00202 else
00203 hp = NULL;
00204
00205 Curl_resolv_unlock(data, dns);
00206
00207 }
00208 if(!hp) {
00209 failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
00210 hostname);
00211 return CURLE_COULDNT_RESOLVE_HOST;
00212 }
00213 }
00214
00215
00216
00217
00218 socksreq[8] = 0;
00219 if (proxy_name)
00220 strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8);
00221
00222
00223
00224
00225 {
00226 ssize_t actualread;
00227 ssize_t written;
00228 int packetsize = 9 +
00229 (int)strlen((char*)socksreq + 8);
00230
00231
00232 code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
00233 if ((code != CURLE_OK) || (written != packetsize)) {
00234 failf(data, "Failed to send SOCKS4 connect request.");
00235 return CURLE_COULDNT_CONNECT;
00236 }
00237
00238 packetsize = 8;
00239
00240
00241 result = blockread_all(conn, sock, (char *)socksreq, packetsize,
00242 &actualread, timeout);
00243 if ((result != CURLE_OK) || (actualread != packetsize)) {
00244 failf(data, "Failed to receive SOCKS4 connect request ack.");
00245 return CURLE_COULDNT_CONNECT;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 if (socksreq[0] != 0) {
00269 failf(data,
00270 "SOCKS4 reply has wrong version, version should be 4.");
00271 return CURLE_COULDNT_CONNECT;
00272 }
00273
00274
00275 switch(socksreq[1])
00276 {
00277 case 90:
00278 infof(data, "SOCKS4 request granted.\n");
00279 break;
00280 case 91:
00281 failf(data,
00282 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00283 ", request rejected or failed.",
00284 (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00285 (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00286 (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
00287 socksreq[1]);
00288 return CURLE_COULDNT_CONNECT;
00289 case 92:
00290 failf(data,
00291 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00292 ", request rejected because SOCKS server cannot connect to "
00293 "identd on the client.",
00294 (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00295 (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00296 (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
00297 socksreq[1]);
00298 return CURLE_COULDNT_CONNECT;
00299 case 93:
00300 failf(data,
00301 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00302 ", request rejected because the client program and identd "
00303 "report different user-ids.",
00304 (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00305 (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00306 (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
00307 socksreq[1]);
00308 return CURLE_COULDNT_CONNECT;
00309 default:
00310 failf(data,
00311 "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
00312 ", Unknown.",
00313 (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00314 (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00315 (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
00316 socksreq[1]);
00317 return CURLE_COULDNT_CONNECT;
00318 }
00319 }
00320
00321 Curl_nonblock(sock, TRUE);
00322
00323 return CURLE_OK;
00324 }
00325
00326
00327
00328
00329
00330 CURLcode Curl_SOCKS5(const char *proxy_name,
00331 const char *proxy_password,
00332 char *hostname,
00333 int remote_port,
00334 int sockindex,
00335 struct connectdata *conn)
00336 {
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 unsigned char socksreq[600];
00355 ssize_t actualread;
00356 ssize_t written;
00357 int result;
00358 CURLcode code;
00359 curl_socket_t sock = conn->sock[sockindex];
00360 struct SessionHandle *data = conn->data;
00361 long timeout;
00362
00363
00364 if(data->set.timeout && data->set.connecttimeout) {
00365 if (data->set.timeout < data->set.connecttimeout)
00366 timeout = data->set.timeout;
00367 else
00368 timeout = data->set.connecttimeout;
00369 }
00370 else if(data->set.timeout)
00371 timeout = data->set.timeout;
00372 else if(data->set.connecttimeout)
00373 timeout = data->set.connecttimeout;
00374 else
00375 timeout = DEFAULT_CONNECT_TIMEOUT;
00376
00377 Curl_nonblock(sock, TRUE);
00378
00379
00380 result = Curl_socket_ready(CURL_SOCKET_BAD, sock, (int)timeout);
00381
00382 if(-1 == result) {
00383 failf(conn->data, "SOCKS5: no connection here");
00384 return CURLE_COULDNT_CONNECT;
00385 }
00386 else if(0 == result) {
00387 failf(conn->data, "SOCKS5: connection timeout");
00388 return CURLE_OPERATION_TIMEDOUT;
00389 }
00390
00391 if(result & CURL_CSELECT_ERR) {
00392 failf(conn->data, "SOCKS5: error occured during connection");
00393 return CURLE_COULDNT_CONNECT;
00394 }
00395
00396 socksreq[0] = 5;
00397 socksreq[1] = (char)(proxy_name ? 2 : 1);
00398 socksreq[2] = 0;
00399 socksreq[3] = 2;
00400
00401 Curl_nonblock(sock, FALSE);
00402
00403 code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
00404 &written);
00405 if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
00406 failf(data, "Unable to send initial SOCKS5 request.");
00407 return CURLE_COULDNT_CONNECT;
00408 }
00409
00410 Curl_nonblock(sock, TRUE);
00411
00412 result = Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout);
00413
00414 if(-1 == result) {
00415 failf(conn->data, "SOCKS5 nothing to read");
00416 return CURLE_COULDNT_CONNECT;
00417 }
00418 else if(0 == result) {
00419 failf(conn->data, "SOCKS5 read timeout");
00420 return CURLE_OPERATION_TIMEDOUT;
00421 }
00422
00423 if(result & CURL_CSELECT_ERR) {
00424 failf(conn->data, "SOCKS5 read error occured");
00425 return CURLE_RECV_ERROR;
00426 }
00427
00428 Curl_nonblock(sock, FALSE);
00429
00430 result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, timeout);
00431 if ((result != CURLE_OK) || (actualread != 2)) {
00432 failf(data, "Unable to receive initial SOCKS5 response.");
00433 return CURLE_COULDNT_CONNECT;
00434 }
00435
00436 if (socksreq[0] != 5) {
00437 failf(data, "Received invalid version in initial SOCKS5 response.");
00438 return CURLE_COULDNT_CONNECT;
00439 }
00440 if (socksreq[1] == 0) {
00441
00442 ;
00443 }
00444 else if (socksreq[1] == 2) {
00445
00446 size_t userlen, pwlen;
00447 int len;
00448 if(proxy_name && proxy_password) {
00449 userlen = strlen(proxy_name);
00450 pwlen = strlen(proxy_password);
00451 }
00452 else {
00453 userlen = 0;
00454 pwlen = 0;
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464 len = 0;
00465 socksreq[len++] = 1;
00466 socksreq[len++] = (char) userlen;
00467 memcpy(socksreq + len, proxy_name, (int) userlen);
00468 len += userlen;
00469 socksreq[len++] = (char) pwlen;
00470 memcpy(socksreq + len, proxy_password, (int) pwlen);
00471 len += pwlen;
00472
00473 code = Curl_write(conn, sock, (char *)socksreq, len, &written);
00474 if ((code != CURLE_OK) || (len != written)) {
00475 failf(data, "Failed to send SOCKS5 sub-negotiation request.");
00476 return CURLE_COULDNT_CONNECT;
00477 }
00478
00479 result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
00480 timeout);
00481 if ((result != CURLE_OK) || (actualread != 2)) {
00482 failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
00483 return CURLE_COULDNT_CONNECT;
00484 }
00485
00486
00487 if (socksreq[1] != 0) {
00488 failf(data, "User was rejected by the SOCKS5 server (%d %d).",
00489 socksreq[0], socksreq[1]);
00490 return CURLE_COULDNT_CONNECT;
00491 }
00492
00493
00494 }
00495 else {
00496
00497 if (socksreq[1] == 1) {
00498 failf(data,
00499 "SOCKS5 GSSAPI per-message authentication is not supported.");
00500 return CURLE_COULDNT_CONNECT;
00501 }
00502 else if (socksreq[1] == 255) {
00503 if (!proxy_name || !*proxy_name) {
00504 failf(data,
00505 "No authentication method was acceptable. (It is quite likely"
00506 " that the SOCKS5 server wanted a username/password, since none"
00507 " was supplied to the server on this connection.)");
00508 }
00509 else {
00510 failf(data, "No authentication method was acceptable.");
00511 }
00512 return CURLE_COULDNT_CONNECT;
00513 }
00514 else {
00515 failf(data,
00516 "Undocumented SOCKS5 mode attempted to be used by server.");
00517 return CURLE_COULDNT_CONNECT;
00518 }
00519 }
00520
00521
00522 socksreq[0] = 5;
00523 socksreq[1] = 1;
00524 socksreq[2] = 0;
00525 socksreq[3] = 1;
00526
00527 {
00528 struct Curl_dns_entry *dns;
00529 Curl_addrinfo *hp=NULL;
00530 int rc = Curl_resolv(conn, hostname, remote_port, &dns);
00531
00532 if(rc == CURLRESOLV_ERROR)
00533 return CURLE_COULDNT_RESOLVE_HOST;
00534
00535 if(rc == CURLRESOLV_PENDING)
00536
00537 rc = Curl_wait_for_resolv(conn, &dns);
00538
00539
00540
00541
00542
00543 if(dns)
00544 hp=dns->addr;
00545 if (hp) {
00546 char buf[64];
00547 unsigned short ip[4];
00548 Curl_printable_address(hp, buf, sizeof(buf));
00549
00550 if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
00551 &ip[0], &ip[1], &ip[2], &ip[3])) {
00552 socksreq[4] = (unsigned char)ip[0];
00553 socksreq[5] = (unsigned char)ip[1];
00554 socksreq[6] = (unsigned char)ip[2];
00555 socksreq[7] = (unsigned char)ip[3];
00556 }
00557 else
00558 hp = NULL;
00559
00560 Curl_resolv_unlock(data, dns);
00561 }
00562 if(!hp) {
00563 failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
00564 hostname);
00565 return CURLE_COULDNT_RESOLVE_HOST;
00566 }
00567 }
00568
00569 *((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port);
00570
00571 {
00572 const int packetsize = 10;
00573
00574 code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
00575 if ((code != CURLE_OK) || (written != packetsize)) {
00576 failf(data, "Failed to send SOCKS5 connect request.");
00577 return CURLE_COULDNT_CONNECT;
00578 }
00579
00580 result = blockread_all(conn, sock, (char *)socksreq, packetsize,
00581 &actualread, timeout);
00582 if ((result != CURLE_OK) || (actualread != packetsize)) {
00583 failf(data, "Failed to receive SOCKS5 connect request ack.");
00584 return CURLE_COULDNT_CONNECT;
00585 }
00586
00587 if (socksreq[0] != 5) {
00588 failf(data,
00589 "SOCKS5 reply has wrong version, version should be 5.");
00590 return CURLE_COULDNT_CONNECT;
00591 }
00592 if (socksreq[1] != 0) {
00593 failf(data,
00594 "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
00595 (unsigned char)socksreq[4], (unsigned char)socksreq[5],
00596 (unsigned char)socksreq[6], (unsigned char)socksreq[7],
00597 (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
00598 socksreq[1]);
00599 return CURLE_COULDNT_CONNECT;
00600 }
00601 }
00602
00603 Curl_nonblock(sock, TRUE);
00604 return CURLE_OK;
00605 }