Added CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE to libcurl. Set with the
authorDaniel Stenberg <daniel@haxx.se>
Mon, 30 Jan 2006 08:24:07 +0000 (08:24 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 30 Jan 2006 08:24:07 +0000 (08:24 +0000)
curl tool with --local-port. Plain and simply set the range of ports to bind
the local end of connections to. Implemented on to popular demand.

Not extensively tested. Please let me know how it works.

CHANGES
RELEASE-NOTES
docs/curl.1
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/connect.c
lib/url.c
lib/urldata.h
src/main.c

diff --git a/CHANGES b/CHANGES
index bfdb149..d61a42b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,10 @@
                                   Changelog
 
 Daniel (30 January 2006)
+- Added CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE to libcurl. Set with the
+  curl tool with --local-port. Plain and simply set the range of ports to bind
+  the local end of connections to. Implemented on to popular demand.
+
 - Based on an error report by Philippe Vaucher, we no longer count a retried
   connection setup as a follow-redirect. It turns out 1) this fails when a FTP
   connection is re-setup and 2) it does make the max-redirs counter behave
index 151ce61..ef9589c 100644 (file)
@@ -5,12 +5,14 @@ Curl and libcurl 7.15.2
  Available command line options:           109
  Available curl_easy_setopt() options:     125
  Number of public functions in libcurl:    46
- Amount of public web site mirrors:        28
+ Amount of public web site mirrors:        30
  Number of known libcurl bindings:         32
  Number of contributors:                   474
 
 This release includes the following changes:
 
+ o CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE (--local-port) added
+ o Dropped support for the LPRT ftp command
  o Gopher is now officially abandoned as a protocol (lib)curl tries to support.
  o curl_global_init() and curl_global_cleanup() are now using a refcount so
    that it is now legal to call them multiple times. See updated info for
@@ -22,7 +24,7 @@ This release includes the following bugfixes:
    redirect and thus prevents a weird error that would occur if a FTP
    connection died on an attempted re-use
  o Try PASV after failing to connect to the port the EPSV response contained
- o -P [IP] with ipv6-enabled curl
+ o -P [IP] with non-local address with ipv6-enabled curl
  o -P [hostname] with ipv6-disabled curl
  o libcurl.m4 was updated
  o configure no longer warns if the current path contains a space
index 598b15d..52949c3 100644 (file)
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -100,7 +100,7 @@ most secure one the remote site claims it supports. This is done by first
 doing a request and checking the response-headers, thus inducing an extra
 network round-trip. This is used instead of setting a specific authentication
 method, which you can do with \fI--basic\fP, \fI--digest\fP, \fI--ntlm\fP, and
-\fI--negotiate\fP. (Added in 7.10.6)
+\fI--negotiate\fP.
 
 Note that using --anyauth is not recommended if you do uploads from stdin,
 since it may require data to be sent twice and then the client must be able to
@@ -140,7 +140,7 @@ If this option is used twice, the second one will disable ASCII usage.
 (HTTP) Tells curl to use HTTP Basic authentication. This is the default and
 this option is usually pointless, unless you use it to override a previously
 set option that sets a different authentication method (such as \fI--ntlm\fP,
-\fI--digest\fP and \fI--negotiate\fP). (Added in 7.10.6)
+\fI--digest\fP and \fI--negotiate\fP).
 
 If this option is used several times, the following occurrences make no
 difference.
@@ -243,7 +243,7 @@ append data.
 prevents the password from being sent over the wire in clear text. Use this in
 combination with the normal \fI-u/--user\fP option to set user name and
 password. See also \fI--ntlm\fP, \fI--negotiate\fP and \fI--anyauth\fP for
-related options. (Added in curl 7.10.6)
+related options.
 
 If this option is used several times, the following occurrences make no
 difference.
@@ -253,7 +253,7 @@ active FTP transfers. Curl will normally always first attempt to use EPRT,
 then LPRT before using PORT, but with this option, it will use PORT right
 away. EPRT and LPRT are extensions to the original FTP protocol, may not work
 on all servers but enable more functionality in a better way than the
-traditional PORT command. (Added in 7.10.5)
+traditional PORT command.
 
 If this option is used several times, each occurrence will toggle this on/off.
 .IP "--disable-epsv"
@@ -351,7 +351,7 @@ If this option is used twice, the second will override the previous use.
 .IP "--ftp-create-dirs"
 (FTP) When an FTP URL/operation uses a path that doesn't currently exist on
 the server, the standard behavior of curl is to fail. Using this option, curl
-will instead attempt to create missing directories. (Added in 7.10.7)
+will instead attempt to create missing directories.
 
 If this option is used twice, the second will again disable directory creation.
 .IP "--ftp-pasv"
@@ -484,15 +484,14 @@ If this option is used twice, the second will again disable header only.
 (HTTP) When curl is told to read cookies from a given file, this option will
 make it discard all "session cookies". This will basically have the same effect
 as if a new session is started. Typical browsers always discard session
-cookies when they're closed down. (Added in 7.9.7)
+cookies when they're closed down.
 
 If this option is used several times, each occurrence will toggle this on/off.
 .IP "-k/--insecure"
 (SSL) This option explicitly allows curl to perform "insecure" SSL connections
-and transfers. Starting with curl 7.10, all SSL connections will be attempted
-to be made secure by using the CA certificate bundle installed by
-default. This makes all connections considered "insecure" to fail unless
-\fI-k/--insecure\fP is used.
+and transfers. All SSL connections are attempted to be made secure by using
+the CA certificate bundle installed by default. This makes all connections
+considered "insecure" to fail unless \fI-k/--insecure\fP is used.
 
 If this option is used twice, the second time will again disable it.
 .IP "--key <key>"
@@ -559,8 +558,6 @@ If you are also using the \fI-Y/--speed-limit\fP option, that option will take
 precedence and might cripple the rate-limiting slightly, to help keeping the
 speed-limit logic working.
 
-This option was introduced in curl 7.10.
-
 If this option is used several times, the last one will be used.
 .IP "-l/--list-only"
 (FTP)
@@ -574,6 +571,11 @@ list only files in their response to NLST; they do not include
 subdirectories and symbolic links.
 
 If this option is used twice, the second will again disable list only.
+.IP "--local-port <num>[-num]"
+Set a prefered number or range of local port numbers to use for the
+connection(s).  Note that port numbers by nature is a scarce resource that
+will be busy at times so setting this range to something too narrow might
+cause unnecessary connection setup failures. (Added in 7.15.2)
 .IP "-L/--location"
 (HTTP/HTTPS) If the server reports that the requested page has moved to a
 different location (indicated with a Location: header and a 3XX response code)
@@ -637,7 +639,7 @@ Very similar to \fI--netrc\fP, but this option makes the .netrc usage
 designed by Microsoft and is used in their web applications. It is primarily
 meant as a support for Kerberos5 authentication but may be also used along
 with another authentication methods. For more information see IETF draft
-draft-brezak-spnego-http-04.txt. (Added in 7.10.6)
+draft-brezak-spnego-http-04.txt.
 
 This option requires that the library was built with GSSAPI support. This is
 not very common. Use \fI-V/--version\fP to see if your version supports
@@ -662,7 +664,7 @@ designed by Microsoft and is used by IIS web servers. It is a proprietary
 protocol, reversed engineered by clever people and implemented in curl based
 on their efforts. This kind of behavior should not be endorsed, you should
 encourage everyone who uses NTLM to switch to a public and documented
-authentication method instead. Such as Digest. (Added in 7.10.6)
+authentication method instead. Such as Digest.
 
 If you want to enable NTLM for your proxy authentication, then use
 \fI--proxy-ntlm\fP.
@@ -702,8 +704,8 @@ You may use this option as many times as you have number of URLs.
 If this option is used several times, the last one will be used.
 .IP "--proxy-anyauth"
 Tells curl to pick a suitable authentication method when communicating with
-the given proxy. This will cause an extra request/response round-trip. Added
-in curl 7.13.2.
+the given proxy. This will cause an extra request/response round-trip. (Added
+in 7.13.2)
 
 If this option is used twice, the second will again disable the proxy use-any
 authentication.
@@ -894,13 +896,10 @@ this is used on a http(s) server, the PUT command will be used.
 
 Use the file name "-" (a single dash) to use stdin instead of a given file.
 
-Before 7.10.8, when this option was used several times, the last one was used.
-
-In curl 7.10.8 and later, you can specify one -T for each URL on the command
-line. Each -T + URL pair specifies what to upload and to where. curl also
-supports "globbing" of the -T argument, meaning that you can upload multiple
-files to a single URL by using the same URL globbing style supported in the
-URL, like this:
+You can specify one -T for each URL on the command line. Each -T + URL pair
+specifies what to upload and to where. curl also supports "globbing" of the -T
+argument, meaning that you can upload multiple files to a single URL by using
+the same URL globbing style supported in the URL, like this:
 
 curl -T "{file1,file2}" http://www.uploadtothissite.com
 
@@ -911,7 +910,6 @@ curl -T "img[1-1000].png" ftp://ftp.picturemania.com/upload/
 Enables a full trace dump of all incoming and outgoing data, including
 descriptive information, to the given output file. Use "-" as filename to have
 the output sent to stdout.
-(Added in 7.9.7)
 
 If this option is used several times, the last one will be used.
 .IP "--trace-ascii <file>"
@@ -922,7 +920,6 @@ the output sent to stdout.
 This is very similar to \fI--trace\fP, but leaves out the hex part and only
 shows the ASCII part of the dump. It makes smaller output that might be easier
 to read for untrained humans.
-(Added in 7.9.7)
 
 If this option is used several times, the last one will be used.
 .IP "--trace-time"
@@ -1083,7 +1080,7 @@ The average download speed that curl measured for the complete download.
 The average upload speed that curl measured for the complete upload.
 .TP
 .B content_type
-The Content-Type of the requested document, if there was any. (Added in 7.9.5)
+The Content-Type of the requested document, if there was any.
 .TP
 .B num_connects
 Number of new connects made in the recent transfer. (Added in 7.12.3)
@@ -1182,11 +1179,11 @@ Note that not all FTP server allow 3rd party transfers. (Added in 7.13.0)
 .IP "-4/--ipv4"
 If libcurl is capable of resolving an address to multiple IP versions (which
 it is if it is ipv6-capable), this option tells libcurl to resolve names to
-IPv4 addresses only. (Added in 7.10.8)
+IPv4 addresses only.
 .IP "-6/--ipv6"
 If libcurl is capable of resolving an address to multiple IP versions (which
 it is if it is ipv6-capable), this option tells libcurl to resolve names to
-IPv6 addresses only. (Added in 7.10.8)
+IPv6 addresses only.
 .IP "-#/--progress-bar"
 Make curl display progress information as a progress bar instead of the
 default statistics.
index 60068f6..25e7e77 100644 (file)
@@ -21,7 +21,7 @@
 .\" * $Id$
 .\" **************************************************************************
 .\"
-.TH curl_easy_setopt 3 "27 Oct 2005" "libcurl 7.14.2" "libcurl Manual"
+.TH curl_easy_setopt 3 "28 Jan 2006" "libcurl 7.15.2" "libcurl Manual"
 .SH NAME
 curl_easy_setopt \- set options for a curl easy handle
 .SH SYNOPSIS
@@ -335,6 +335,19 @@ don't want this tunneling option.
 Pass a char * as parameter. This set the interface name to use as outgoing
 network interface. The name can be an interface name, an IP address or a host
 name.
+.IP CURLOPT_LOCALPORT
+Pass a long. This sets the local port number of the socket used for
+connection. This can be used in combination with \fICURLOPT_INTERFACE\fP and
+you are recommended to use \fICURLOPT_LOCALPORTRANGE\fP as well when this is
+set. Note that port numbers are only valid 1 - 65535. (Added in 7.15.2)
+.IP CURLOPT_LOCALPORTRANGE
+Pass a long. This is the number of attempts libcurl should do to find a
+working local port number. It starts with the given \fICURLOPT_LOCALPORT\fP
+and adds one to the number for each retry. Setting this value to 1 or below
+will make libcurl do only one try for exact port number. Note that port
+numbers by nature is a scarce resource that will be busy at times so setting
+this value to something too low might cause unnecessary connection setup
+failures. (Added in 7.15.2)
 .IP CURLOPT_DNS_CACHE_TIMEOUT
 Pass a long, this sets the timeout in seconds. Name resolves will be kept in
 memory for this number of seconds. Set to zero (0) to completely disable
index 0ac3f28..95c478a 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -915,6 +915,14 @@ typedef enum {
   /* Select "file method" to use when doing FTP */
   CINIT(FTP_FILEMETHOD, LONG, 138),
 
+  /* Local port number to bind the socket to */
+  CINIT(LOCALPORT, LONG, 139),
+
+  /* Number of ports to try, including the first one set with LOCALPORT.
+     Thus, setting it to 1 will make no additional attempts but the first.
+  */
+  CINIT(LOCALPORTRANGE, LONG, 140),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 2fb08d6..902721c 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -98,6 +98,7 @@
 #include "memory.h"
 #include "select.h"
 #include "url.h" /* for Curl_safefree() */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -239,16 +240,20 @@ int waitconnect(curl_socket_t sockfd, /* socket */
 static CURLcode bindlocal(struct connectdata *conn,
                           curl_socket_t sockfd)
 {
-#ifdef HAVE_INET_NTOA
-  bool bindworked = FALSE;
   struct SessionHandle *data = conn->data;
+  struct sockaddr_in me;
+  struct sockaddr *sock = NULL;  /* bind to this address */
+  socklen_t socksize; /* size of the data sock points to */
+  unsigned short port = data->set.localport; /* use this port number, 0 for
+                                                "random" */
+  /* how many port numbers to try to bind to, increasing one at a time */
+  int portnum = data->set.localportrange;
 
   /*************************************************************
    * Select device to bind socket to
    *************************************************************/
-  if (strlen(data->set.device)<255) {
+  if (data->set.device && (strlen(data->set.device)<255) ) {
     struct Curl_dns_entry *h=NULL;
-    size_t size;
     char myhost[256] = "";
     in_addr_t in;
     int rc;
@@ -266,8 +271,10 @@ static CURLcode bindlocal(struct connectdata *conn,
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_wait_for_resolv(conn, &h);
 
-      if(h)
+      if(h) {
         was_iface = TRUE;
+        Curl_resolv_unlock(data, h);
+      }
     }
 
     if(!was_iface) {
@@ -279,9 +286,11 @@ static CURLcode bindlocal(struct connectdata *conn,
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_wait_for_resolv(conn, &h);
 
-      if(h)
+      if(h) {
         /* we know data->set.device is shorter than the myhost array */
         strcpy(myhost, data->set.device);
+        Curl_resolv_unlock(data, h);
+      }
     }
 
     if(! *myhost) {
@@ -295,7 +304,7 @@ static CURLcode bindlocal(struct connectdata *conn,
       return CURLE_HTTP_PORT_FAILED;
     }
 
-    infof(data, "We bind local end to %s\n", myhost);
+    infof(data, "Bind local address to %s\n", myhost);
 
 #ifdef SO_BINDTODEVICE
     /* I am not sure any other OSs than Linux that provide this feature, and
@@ -323,60 +332,79 @@ static CURLcode bindlocal(struct connectdata *conn,
 #endif
 
     in=inet_addr(myhost);
-    if (CURL_INADDR_NONE != in) {
+    if (CURL_INADDR_NONE == in) {
+      failf(data,"couldn't find my own IP address (%s)", myhost);
+      return CURLE_HTTP_PORT_FAILED;
+    } /* end of inet_addr */
 
-      if ( h ) {
-        Curl_addrinfo *addr = h->addr;
+    if ( h ) {
+      Curl_addrinfo *addr = h->addr;
+      sock = addr->ai_addr;
+      socksize = addr->ai_addrlen;
+    }
+    else
+      return CURLE_HTTP_PORT_FAILED;
 
-        Curl_resolv_unlock(data, h);
-        /* we don't need it anymore after this function has returned */
+  }
+  else if(port) {
+    /* if a local port number is requested but no local IP, extract the
+       address from the socket */
+    memset(&me, 0, sizeof(struct sockaddr));
+    me.sin_family = AF_INET;
+    me.sin_addr.s_addr = INADDR_ANY;
 
-        if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
-          /* we succeeded to bind */
-#ifdef ENABLE_IPV6
-          struct sockaddr_in6 add;
-#else
-          struct sockaddr_in add;
-#endif
+    sock = (struct sockaddr *)&me;
+    socksize = sizeof(struct sockaddr);
 
-          bindworked = TRUE;
+  }
+  else
+    /* no local kind of binding was requested */
+    return CURLE_OK;
 
-          size = sizeof(add);
-          if(getsockname(sockfd, (struct sockaddr *) &add,
-                         (socklen_t *)&size)<0) {
-            failf(data, "getsockname() failed");
-            return CURLE_HTTP_PORT_FAILED;
-          }
-        }
+  do {
 
-        if(!bindworked) {
-          data->state.os_errno = Curl_ourerrno();
-          failf(data, "bind failure: %s",
-                Curl_strerror(conn, data->state.os_errno));
-          return CURLE_HTTP_PORT_FAILED;
-        }
+    /* Set port number to bind to, 0 makes the system pick one */
+    if(sock->sa_family == AF_INET)
+      ((struct sockaddr_in *)sock)->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+    else
+      ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
+#endif
 
-      } /* end of if  h */
-      else {
-        failf(data,"couldn't find my own IP address (%s)", myhost);
+    if( bind(sockfd, sock, socksize) >= 0) {
+      /* we succeeded to bind */
+      struct Curl_sockaddr_storage add;
+      unsigned short port;
+      size_t size;
+
+      size = sizeof(add);
+      if(getsockname(sockfd, (struct sockaddr *) &add,
+                     (socklen_t *)&size)<0) {
+        failf(data, "getsockname() failed");
         return CURLE_HTTP_PORT_FAILED;
       }
-    } /* end of inet_addr */
-
-    else {
-      failf(data, "couldn't find my own IP address (%s)", myhost);
-      return CURLE_HTTP_PORT_FAILED;
+      if(((struct sockaddr *)&add)->sa_family == AF_INET)
+        port = ntohs(((struct sockaddr_in *)&add)->sin_port);
+#ifdef ENABLE_IPV6
+      else
+        port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
+#endif
+      infof(data, "Local port: %d\n", port);
+      return CURLE_OK;
     }
+    if(--portnum > 0) {
+      infof(data, "Bind to local port %d failed, trying next\n", port);
+      port++; /* try next port */
+    }
+    else
+      break;
+  } while(1);
 
-    return CURLE_OK;
-
-  } /* end of device selection support */
-#else
-  (void)conn;
-  (void)sockfd;
-#endif /* end of HAVE_INET_NTOA */
-
+  data->state.os_errno = Curl_ourerrno();
+  failf(data, "bind failure: %s",
+        Curl_strerror(conn, data->state.os_errno));
   return CURLE_HTTP_PORT_FAILED;
+
 }
 
 /*
@@ -618,6 +646,8 @@ static void nosigpipe(struct connectdata *conn,
     infof(data, "Could not set SO_NOSIGPIPE: %s\n",
           Curl_strerror(conn, Curl_ourerrno()));
 }
+#else
+#define nosigpipe(x,y)
 #endif
 
 /* singleipconnect() connects to the given IP only, and it may return without
@@ -634,6 +664,7 @@ singleipconnect(struct connectdata *conn,
   bool isconnected;
   struct SessionHandle *data = conn->data;
   curl_socket_t sockfd;
+  CURLcode res;
 
   sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
   if (sockfd == CURL_SOCKET_BAD)
@@ -647,17 +678,13 @@ singleipconnect(struct connectdata *conn,
   if(data->set.tcp_nodelay)
     tcpnodelay(conn, sockfd);
 
-#ifdef SO_NOSIGPIPE
   nosigpipe(conn, sockfd);
-#endif
-  if(conn->data->set.device) {
-    /* user selected to bind the outgoing socket to a specified "device"
-       before doing connect */
-    CURLcode res = bindlocal(conn, sockfd);
-    if(res) {
-      sclose(sockfd); /* close socket and bail out */
-      return CURL_SOCKET_BAD;
-    }
+
+  /* possibly bind the local end to an IP, interface or port */
+  res = bindlocal(conn, sockfd);
+  if(res) {
+    sclose(sockfd); /* close socket and bail out */
+    return CURL_SOCKET_BAD;
   }
 
   /* set socket non-blocking */
index a4bd0f5..f17213f 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1222,13 +1222,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     data->set.crlf = va_arg(param, long)?TRUE:FALSE;
     break;
+
   case CURLOPT_INTERFACE:
     /*
-     * Set what interface to bind to when performing an operation and thus
-     * what from-IP your connection will use.
+     * Set what interface or address/hostname to bind the socket to when
+     * performing an operation and thus what from-IP your connection will use.
      */
     data->set.device = va_arg(param, char *);
     break;
+  case CURLOPT_LOCALPORT:
+    /*
+     * Set what local port to bind the socket to when performing an operation.
+     */
+    data->set.localport = (unsigned short) va_arg(param, long);
+    break;
+  case CURLOPT_LOCALPORTRANGE:
+    /*
+     * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+     */
+    data->set.localportrange = (int) va_arg(param, long);
+    break;
   case CURLOPT_KRB4LEVEL:
     /*
      * A string that defines the krb4 security level.
index c3a76b4..96494a7 100644 (file)
@@ -970,7 +970,10 @@ struct UserDefined {
                                of strlen(), and then the data *may* be binary
                                (contain zero bytes) */
   char *ftpport;     /* port to send with the FTP PORT command */
-  char *device;      /* network interface to use */
+  char *device;      /* local network interface/address to use */
+  unsigned short localport; /* local port number to bind to */
+  int localportrange; /* number of additional port numbers to test in case the
+                         'localport' one can't be bind()ed */
   curl_write_callback fwrite;        /* function that stores the output */
   curl_write_callback fwrite_header; /* function that stores headers */
   curl_read_callback fread;          /* function that reads the input */
index 38eb9f0..549a4d8 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -271,6 +271,8 @@ struct Configurable {
   char *headerfile;
   char *ftpport;
   char *iface;
+  int localport;
+  int localportrange;
   unsigned short porttouse;
   char *range;
   long low_speed_limit;
@@ -519,12 +521,13 @@ static void help(void)
     " -i/--include       Include protocol headers in the output (H/F)",
     " -I/--head          Show document info only",
     " -j/--junk-session-cookies Ignore session cookies read from file (H)",
-    "    --interface <interface> Specify network interface to use",
+    "    --interface <interface> Specify network interface/address to use",
     "    --krb4 <level>  Enable krb4 with specified security level (F)",
     " -k/--insecure      Allow connections to SSL sites without certs (H)",
     " -K/--config        Specify which config file to read",
     " -l/--list-only     List only names of an FTP directory (F)",
     "    --limit-rate <rate> Limit transfer speed to this rate",
+    "    --local-port <num>[-num] Force use of these local port numbers\n",
     " -L/--location      Follow Location: hints (H)",
     "    --location-trusted Follow Location: and send authentication even ",
     "                    to other hostnames (H)",
@@ -1261,7 +1264,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
 {
   char letter;
   char subletter=0; /* subletters can only occur on long options */
-
+  int rc; /* generic return code variable */
   const char *parse=NULL;
   unsigned int j;
   time_t now;
@@ -1326,6 +1329,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
     {"$p", "ignore-content-length", FALSE},
     {"$q", "ftp-skip-pasv-ip", FALSE},
     {"$r", "ftp-method", TRUE},
+    {"$s", "local-port", TRUE},
 
     {"0", "http1.0",     FALSE},
     {"1", "tlsv1",       FALSE},
@@ -1739,6 +1743,22 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
       case 'r': /* --ftp-method (undocumented at this point) */
         config->ftp_filemethod = ftpfilemethod(config, nextarg);
         break;
+      case 's': /* --local-port */
+        rc = sscanf(nextarg, "%d - %d",
+                    &config->localport,
+                    &config->localportrange);
+        if(!rc)
+          return PARAM_BAD_USE;
+        else if(rc == 1)
+          config->localportrange = 1; /* default number of ports to try */
+        else {
+          config->localportrange -= config->localport;
+          if(config->localportrange < 1) {
+            warnf(config, "bad range input\n");
+            return PARAM_BAD_USE;
+          }
+        }
+        break;
       }
       break;
     case '#': /* --progress-bar */
@@ -3972,6 +3992,12 @@ operate(struct Configurable *config, int argc, char *argv[])
         /* curl 7.15.1 */
         curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
 
+        /* curl 7.15.2 */
+        if(config->localport) {
+          curl_easy_setopt(curl, CURLOPT_LOCALPORT, config->localport);
+          curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, config->localportrange);
+        }
+
         retry_numretries = config->req_retry;
 
         retrystart = curlx_tvnow();