Commit a15d107d authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Peter Su added support for SOCKS4 proxies. Enable this by setting the proxy

type to the already provided type CURLPROXY_SOCKS4.
I added a --socks4 option that works like the current --socks5 option but
instead use the socks4 protocol.
parent 09897b81
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -6,6 +6,13 @@

                                  Changelog

Daniel (21 February 2006)
- Peter Su added support for SOCKS4 proxies. Enable this by setting the proxy
  type to the already provided type CURLPROXY_SOCKS4.

  I added a --socks4 option that works like the current --socks5 option but
  instead use the socks4 protocol.

Daniel (20 February 2006)
- Shmulik Regev fixed an issue with multi-pass authentication and compressed
  content when libcurl didn't honor the internal ignorebody flag.
+3 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@ Curl and libcurl 7.15.2

 Public curl release number:               92
 Releases counted from the very beginning: 119
 Available command line options:           111
 Available command line options:           112
 Available curl_easy_setopt() options:     129
 Number of public functions in libcurl:    46
 Amount of public web site mirrors:        31
@@ -11,6 +11,7 @@ Curl and libcurl 7.15.2

This release includes the following changes:

 o Support for SOCKS4 proxies (added --socks4)
 o CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET added
 o CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE (--local-port) added
 o Dropped support for the LPRT ftp command
@@ -65,6 +66,6 @@ advice from friends like these:
 Dov Murik, Jean Jacques Drouin, Andres Garcia, Yang Tse, Gisle Vanem, Dan
 Fandrich, Alexander Lazic, Michael Jahn, Andrew Benham, Bryan Henderson,
 David Shaw, Jon Turner, Duane Cathey, Michal Marek, Philippe Vaucher, Kent
 Boortz, Karl Moerder, Shmulik Regev, Ulf Härnhammar, Shmulik Regev
 Boortz, Karl Moerder, Shmulik Regev, Ulf Härnhammar, Peter Su
 
        Thanks! (and sorry if I forgot to mention someone)
+13 −3
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
.\" * $Id$
.\" **************************************************************************
.\"
.TH curl 1 "24 Nov 2005" "Curl 7.15.1" "Curl Manual"
.TH curl 1 "21 Feb 2006" "Curl 7.15.2" "Curl Manual"
.SH NAME
curl \- transfer a URL
.SH SYNOPSIS
@@ -859,14 +859,24 @@ If this option is used twice, the second will again disable silent mode.
When used with -s it makes curl show error message if it fails.

If this option is used twice, the second will again disable show error.
.IP "--socks <host[:port]>"
.IP "--socks4 <host[:port]>"
Use the specified SOCKS4 proxy. If the port number is not specified, it is
assumed at port 1080. (Added in 7.15.2)

This option overrides any previous use of \fI-x/--proxy\fP, as they are
mutually exclusive.

If this option is used several times, the last one will be used.
.IP "--socks5 <host[:port]>"
Use the specified SOCKS5 proxy. If the port number is not specified, it is
assumed at port 1080. (Added in 7.11.1)

This option overrides any previous use of \fI-x/--proxy\fP, as they are
mutually exclusive.

If this option is used several times, the last one will be used.
If this option is used several times, the last one will be used. (This option
was previously wrongly documented and used as --socks without the number
appended.)
.IP "--stderr <file>"
Redirect all writes to stderr to the specified file instead. If the file name
is a plain '-', it is instead written to stdout. This option has no point when
+3 −3
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
.\" * $Id$
.\" **************************************************************************
.\"
.TH curl_easy_setopt 3 "28 Jan 2006" "libcurl 7.15.2" "libcurl Manual"
.TH curl_easy_setopt 3 "21 Feb 2006" "libcurl 7.15.2" "libcurl Manual"
.SH NAME
curl_easy_setopt \- set options for a curl easy handle
.SH SYNOPSIS
@@ -324,8 +324,8 @@ Pass a long with this option to set the proxy port to connect to unless it is
specified in the proxy string \fICURLOPT_PROXY\fP.
.IP CURLOPT_PROXYTYPE
Pass a long with this option to set type of the proxy. Available options for
this are \fICURLPROXY_HTTP\fP and \fICURLPROXY_SOCKS5\fP, with the HTTP one
being default. (Added in 7.10)
this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_SOCKS4\fP (added in 7.15.2)
\fICURLPROXY_SOCKS5\fP. The HTTP type is default. (Added in 7.10)
.IP CURLOPT_HTTPPROXYTUNNEL
Set the parameter to non-zero to get the library to tunnel all operations
through a given HTTP proxy. There is a big difference between using a proxy
+192 −5
Original line number Diff line number Diff line
@@ -1809,6 +1809,191 @@ ConnectionStore(struct SessionHandle *data,
  return i;
}

/*
* This function logs in to a SOCKS4 proxy and sends the specifies the final
* desitination server.
*
* Reference :
*   http://socks.permeo.com/protocol/socks4.protocol
*
* Note :
*   Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
*   Nonsupport "Identification Protocol (RFC1413)"
*/
static int handleSock4Proxy(struct connectdata *conn)
{
  unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
  int result;
  CURLcode code;
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
  struct SessionHandle *data = conn->data;

  Curl_nonblock(sock, FALSE);

  /*
  * Compose socks4 request
  *
  * Request format
  *
  *     +----+----+----+----+----+----+----+----+----+----+....+----+
  *     | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
  *     +----+----+----+----+----+----+----+----+----+----+....+----+
  * # of bytes:  1    1      2              4           variable       1
  */

  socksreq[0] = 4; /* version (SOCKS4) */
  socksreq[1] = 1; /* connect */
  *((unsigned short*)&socksreq[2]) = htons(conn->remote_port);

  /* DNS resolve */
  {
    struct Curl_dns_entry *dns;
    Curl_addrinfo *hp=NULL;
    int rc;

    rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);

    if(rc == CURLRESOLV_ERROR)
      return 1;

    if(rc == CURLRESOLV_PENDING)
      /* this requires that we're in "wait for resolve" state */
      rc = Curl_wait_for_resolv(conn, &dns);

    /*
    * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
    * returns a Curl_addrinfo pointer that may not always look the same.
    */
    if(dns)
      hp=dns->addr;
    if (hp) {
      char buf[64];
      unsigned short ip[4];
      Curl_printable_address(hp, buf, sizeof(buf));

      if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
        &ip[0], &ip[1], &ip[2], &ip[3])) {
          /* Set DSTIP */
          socksreq[4] = (unsigned char)ip[0];
          socksreq[5] = (unsigned char)ip[1];
          socksreq[6] = (unsigned char)ip[2];
          socksreq[7] = (unsigned char)ip[3];
        }
      else
        hp = NULL; /* fail! */

      Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */

    }
    if(!hp) {
      failf(conn->data, "Failed to resolve \"%s\" for SOCKS4 connect.\n",
        conn->host.name);
      return 1;
    }
  }

  /*
  * Make connection
  */
  {
    ssize_t actualread;
    ssize_t written;
    int packetsize = 9; /* request data size (include NULL) */

    /* Send request */
    code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
    if ((code != CURLE_OK) || (written != packetsize)) {
      failf(conn->data, "Failed to send SOCKS4 connect request.\n");
      return 1;
    }

    packetsize = 8; /* receive data size */

    /* Receive response */
    result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
    if ((result != CURLE_OK) || (actualread != packetsize)) {
      failf(conn->data, "Failed to receive SOCKS4 connect request ack.\n");
      return 1;
    }

    /*
    * Response format
    *
    *     +----+----+----+----+----+----+----+----+
    *     | VN | CD | DSTPORT |      DSTIP        |
    *     +----+----+----+----+----+----+----+----+
    * # of bytes:  1    1      2              4
    *
    * VN is the version of the reply code and should be 0. CD is the result
    * code with one of the following values:
    *
    * 90: request granted
    * 91: request rejected or failed
    * 92: request rejected becasue SOCKS server cannot connect to
    *     identd on the client
    * 93: request rejected because the client program and identd
    *     report different user-ids
    */

    /* wrong version ? */
    if (socksreq[0] != 0) {
      failf(conn->data,
        "SOCKS4 reply has wrong version, version should be 4.\n");
      return 1;
    }

    /* Result */
    switch(socksreq[1])
    {
      case 90:
        infof(data, "SOCKS4 request granted.\n");
        break;
      case 91:
        failf(conn->data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected or failed.\n",
          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
          (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
          socksreq[1]);
        return 1;
      case 92:
        failf(conn->data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected becasue SOCKS server cannot connect to "
          "identd on the client.\n",
          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
          (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
          socksreq[1]);
        return 1;
      case 93:
        failf(conn->data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected because the client program and identd "
          "report different user-ids.\n",
          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
          (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
          socksreq[1]);
        return 1;
      default :
        failf(conn->data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", Unknown.\n",
          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
          (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
          socksreq[1]);
        return 1;
    }
  }

  Curl_nonblock(sock, TRUE);

  return 0; /* Proxy was successful! */
}

/*
 * This function logs in to a SOCKS5 proxy and sends the specifies the final
 * desitination server.
@@ -2052,16 +2237,18 @@ static CURLcode ConnectPlease(struct connectdata *conn,

    Curl_store_ip_addr(conn);

    if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
    switch(conn->data->set.proxytype) {
    case CURLPROXY_SOCKS5:
      return handleSock5Proxy(conn->proxyuser,
                              conn->proxypasswd,
                              conn) ?
        CURLE_COULDNT_CONNECT : CURLE_OK;
    }
    else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
    case CURLPROXY_HTTP:
      /* do nothing here. handled later. */
    }
    else {
      break;
    case CURLPROXY_SOCKS4:
      return handleSock4Proxy(conn) ? CURLE_COULDNT_CONNECT : CURLE_OK;
    default:
      failf(conn->data, "unknown proxytype option given");
      return CURLE_COULDNT_CONNECT;
    }
Loading