]> granicus.if.org Git - curl/commitdiff
- Craig A West brought CURLOPT_NOPROXY and the corresponding --noproxy option.
authorDaniel Stenberg <daniel@haxx.se>
Sun, 25 Jan 2009 23:26:25 +0000 (23:26 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 25 Jan 2009 23:26:25 +0000 (23:26 +0000)
  They basically offer the same thing the NO_PROXY environment variable only
  offered previously: list a set of host names that shall not use the proxy
  even if one is specified.

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

diff --git a/CHANGES b/CHANGES
index 4c40fd5a0009bbcd8a7626ccdb276cda7cbdd95c..e65da208f3816352fac902ebb92300f394d26fd1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,12 @@
 
                                   Changelog
 
+Daniel Stenberg (26 Jan 2009)
+- Craig A West brought CURLOPT_NOPROXY and the corresponding --noproxy option.
+  They basically offer the same thing the NO_PROXY environment variable only
+  offered previously: list a set of host names that shall not use the proxy
+  even if one is specified.
+
 Daniel Fandrich (20 Jan 2009)
 - Call setlocale() for libtest tests to test the effects of locale-induced
   libc changes on libcurl.
@@ -20,8 +26,8 @@ Daniel Fandrich (20 Jan 2009)
   locale.
 
 Daniel Stenberg (20 Jan 2009)
-- Lisa Xu pointed out that the ssh.obj file was missing from the lib/Makefile.vc6
-  file (and thus from the vc8 and vc9 ones too). 
+- Lisa Xu pointed out that the ssh.obj file was missing from the
+  lib/Makefile.vc6 file (and thus from the vc8 and vc9 ones too).
 
 Version 7.19.3 (19 January 2009)
 
index 8f29683ec83f457b09cf387e666276f4eeb3de28..bb76da6970ca1d67add008770c7a77ba452d20e8 100644 (file)
@@ -1,15 +1,15 @@
 Curl and libcurl 7.19.4
 
  Public curl releases:         110
- Command line options:         128
- curl_easy_setopt() options:   158
+ Command line options:         129
+ curl_easy_setopt() options:   159
  Public functions in libcurl:  58
  Known libcurl bindings:       37
  Contributors:                 700
 
 This release includes the following changes:
 
- o 
+ o Added CURLOPT_NOPROXY and the corresponding --noproxy
 
 This release includes the following bugfixes:
 
@@ -23,6 +23,6 @@ This release includes the following known bugs:
 This release would not have looked like this without help, code, reports and
 advice from friends like these:
 
- Lisa Xu
+ Lisa Xu, Daniel Fandrich, Craig A West
 
         Thanks! (and sorry if I forgot to mention someone)
index 70fbf7b29e74d8ad9c54e0eb1b27a7928f6d349b..decf186ffec5bc85759a92785692f690c162dd9b 100644 (file)
@@ -1,8 +1,6 @@
 To be addressed in 7.19.4 (planned release: March 2009)
 =========================
 
-205 - A. Craig West's CURLOPT_NOPROXY option
-
 206 - A. Craig West's CURLOPT_HTTP_VERSION change for CONNECT
 
 208 - Patch to allow GSSAPI authentication to a socks5 server
index 3aea5d40f41d115927ccd6fd3e4fa734d8f0fd2b..de2bdd28026e4b1c99be7bd20443d1dad7c91f0b 100644 (file)
@@ -136,6 +136,11 @@ PROXY
 
         curl -U user:passwd -x my-proxy:888 http://www.get.this/
 
+ A comma-separated list of hosts and domains which do not use the proxy can
+ be specified as:
+
+        curl --noproxy localhost,get.this -x my-proxy:888 http://www.get.this/
+
  curl also supports SOCKS4 and SOCKS5 proxies with --socks4 and --socks5.
 
  See also the environment variables Curl support that offer further proxy
@@ -793,8 +798,9 @@ ENVIRONMENT VARIABLES
 
         NO_PROXY
 
-  If a tail substring of the domain-path for a host matches one of these
-  strings, transactions with that node will not be proxied.
+  If the host name matches one of these strings, or the host is within the
+  domain of one of these strings, transactions with that node will not be
+  proxied.
 
 
   The usage of the -x/--proxy flag overrides the environment variables.
index cd9dba9d20975e0549c9e061c92864096178651b..5b7c111f50d4eba995a1cc9d2a58576ae7d5b436 100644 (file)
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" * Copyright (C) 1998 - 2009, 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
@@ -815,6 +815,13 @@ you to succeed. (Added in 7.16.0)
 
 Note that this is the negated option name documented. You can thus use
 \fI--sessionid\fP to enforce session-ID caching.
+.IP "--noproxy <no-proxy-list>"
+Comma-separated list of hosts which do not use a proxy, if one is specified.
+The only wildcard is a single * character, which matches all hosts, and
+effectively disables the proxy. Each name in this list is matched as either
+a domain which contains the hostname, or the hostname itself. For example,
+local.com would match local.com, local.com:80, and www.local.com, but not
+www.notlocal.com.
 .IP "--ntlm"
 (HTTP) Enables NTLM authentication. The NTLM authentication method was
 designed by Microsoft and is used by IIS web servers. It is a proprietary
index 5aa64f553dbe25a67b0e39600430b4767e979028..c9bc0365cebf2d682223ce554b3e98685c8094a8 100644 (file)
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" * Copyright (C) 1998 - 2009, 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
@@ -474,6 +474,14 @@ this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_SOCKS4\fP (added in 7.15.2),
 \fICURLPROXY_SOCKS5\fP, \fICURLPROXY_SOCKS4A\fP (added in 7.18.0) and
 \fICURLPROXY_SOCKS5_HOSTNAME\fP (added in 7.18.0). The HTTP type is
 default. (Added in 7.10)
+.IP CURLOPT_NOPROXY
+Pass a pointer to a zero terminated string. The should be a comma- separated
+list of hosts which do not use a proxy, if one is specified.  The only
+wildcard is a single * character, which matches all hosts, and effectively
+disables the proxy. Each name in this list is matched as either a domain which
+contains the hostname, or the hostname itself. For example, local.com would
+match local.com, local.com:80, and www.local.com, but not www.notlocal.com.
+(Added in 7.19.4)
 .IP CURLOPT_HTTPPROXYTUNNEL
 Set the parameter to 1 to make the library tunnel all operations through a
 given HTTP proxy. There is a big difference between using a proxy and to
index e94ff5f9d169a4f792a15c2d916aa582a876db1f..830e8a1d84ff491fbdcf78b36fda02cfce70e2ee 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2009, 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
@@ -1150,6 +1150,15 @@ typedef enum {
   CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
   CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
 
+  /* Comma separated list of hostnames defining no-proxy zones. These should
+     match both hostnames directly, and hostnames within a domain. For
+     example, local.com will match local.com and www.local.com, but NOT
+     notlocal.com or www.notlocal.com. For compatibility with other
+     implementations of this, .local.com will be considered to be the same as
+     local.com. A single * is the only valid wildcard, and effectively
+     disables the use of proxy. */
+  CINIT(NOPROXY, OBJECTPOINT, 177),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 41cc7598e3c43bfc3b6fc852ece9cf2f50620a4b..39fad7acba504f7a072b39b691a06197b2a5673a 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2009, 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
@@ -201,6 +201,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
    (option) == CURLOPT_PROXYUSERPWD ||                                        \
    (option) == CURLOPT_PROXYUSERNAME ||                                       \
    (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_NOPROXY ||                                             \
    (option) == CURLOPT_ENCODING ||                                            \
    (option) == CURLOPT_REFERER ||                                             \
    (option) == CURLOPT_USERAGENT ||                                           \
index 47d2af342c93cd90f078f9b130de6e6be2cb8a46..6cefda2c1039ae83b91679b9c78644825fb489ec 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2009, 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
@@ -1677,6 +1677,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
                        va_arg(param, char *));
     break;
+  case CURLOPT_NOPROXY:
+    /*
+     * proxy exception list
+     */
+    result = setstropt(&data->set.str[STRING_NOPROXY],
+                       va_arg(param, char *));
+    break;
 #endif
 
   case CURLOPT_RANGE:
@@ -3368,6 +3375,80 @@ static CURLcode setup_connection_internals(struct SessionHandle *data,
 }
 
 #ifndef CURL_DISABLE_PROXY
+/****************************************************************
+* Checks if the host is in the noproxy list. returns true if it matches
+* and therefore the proxy should NOT be used.
+****************************************************************/
+static bool check_noproxy(const char* name, const char* no_proxy)
+{
+  /* no_proxy=domain1.dom,host.domain2.dom
+   *   (a comma-separated list of hosts which should
+   *   not be proxied, or an asterisk to override
+   *   all proxy variables)
+   */
+  size_t tok_start;
+  size_t tok_end;
+  const char* separator = ", ";
+  size_t no_proxy_len;
+  size_t namelen;
+  char *endptr;
+
+  if(no_proxy && no_proxy[0]) {
+    if(Curl_raw_equal("*", no_proxy)) {
+      return TRUE;
+    }
+
+    /* NO_PROXY was specified and it wasn't just an asterisk */
+
+    no_proxy_len = strlen(no_proxy);
+    endptr = strchr(name, ':');
+    if(endptr)
+      namelen = endptr - name;
+    else
+      namelen = strlen(name);
+
+    tok_start = 0;
+    for (tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
+      while (tok_start < no_proxy_len &&
+             strchr(separator, no_proxy[tok_start]) != NULL) {
+        /* Look for the beginning of the token. */
+        ++tok_start;
+      }
+
+      if(tok_start == no_proxy_len)
+        break; /* It was all trailing separator chars, no more tokens. */
+
+      for (tok_end = tok_start; tok_end < no_proxy_len &&
+             strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) {
+        /* Look for the end of the token. */
+      }
+
+      /* To match previous behaviour, where it was necessary to specify
+       * ".local.com" to prevent matching "notlocal.com", we will leave
+       * the '.' off.
+       */
+      if(no_proxy[tok_start] == '.')
+        ++tok_start;
+
+      if((tok_end - tok_start) <= namelen) {
+        /* Match the last part of the name to the domain we are checking. */
+        const char *checkn = name + namelen - (tok_end - tok_start);
+        if(Curl_raw_nequal(no_proxy + tok_start, checkn, tok_end - tok_start)) {
+          if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
+            /* We either have an exact match, or the previous character is a .
+             * so it is within the same domain, so no proxy for this host.
+             */
+            return TRUE;
+          }
+        }
+      } /* if((tok_end - tok_start) <= namelen) */
+    } /* for (tok_start = 0; tok_start < no_proxy_len;
+         tok_start = tok_end + 1) */
+  } /* NO_PROXY was specified and it wasn't just an asterisk */
+
+  return FALSE;
+}
+
 /****************************************************************
 * Detect what (if any) proxy to use. Remember that this selects a host
 * name and is not limited to HTTP proxies only.
@@ -3396,90 +3477,56 @@ static char *detect_proxy(struct connectdata *conn)
    * checked if the lowercase versions don't exist.
    */
   char *no_proxy=NULL;
-  char *no_proxy_tok_buf;
   char proxy_env[128];
 
   no_proxy=curl_getenv("no_proxy");
   if(!no_proxy)
     no_proxy=curl_getenv("NO_PROXY");
 
-  if(!no_proxy || !Curl_raw_equal("*", no_proxy)) {
-    /* NO_PROXY wasn't specified or it wasn't just an asterisk */
-    char *nope;
+  if(!check_noproxy(conn->host.name, no_proxy)) {
+    /* It was not listed as without proxy */
+    char *protop = conn->protostr;
+    char *envp = proxy_env;
+    char *prox;
 
-    nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
-    while(nope) {
-      size_t namelen;
-      char *endptr = strchr(conn->host.name, ':');
-      if(endptr)
-        namelen=endptr-conn->host.name;
-      else
-        namelen=strlen(conn->host.name);
-
-      if(strlen(nope) <= namelen) {
-        char *checkn=
-          conn->host.name + namelen - strlen(nope);
-        if(checkprefix(nope, checkn)) {
-          /* no proxy for this host! */
-          break;
-        }
-      }
-      nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
-    }
-    if(!nope) {
-      /* It was not listed as without proxy */
-      char *protop = conn->protostr;
-      char *envp = proxy_env;
-      char *prox;
+    /* Now, build <protocol>_proxy and check for such a one to use */
+    while(*protop)
+      *envp++ = (char)tolower((int)*protop++);
 
-      /* Now, build <protocol>_proxy and check for such a one to use */
-      while(*protop)
-        *envp++ = (char)tolower((int)*protop++);
+    /* append _proxy */
+    strcpy(envp, "_proxy");
 
-      /* append _proxy */
-      strcpy(envp, "_proxy");
+    /* read the protocol proxy: */
+    prox=curl_getenv(proxy_env);
 
-      /* read the protocol proxy: */
+    /*
+     * We don't try the uppercase version of HTTP_PROXY because of
+     * security reasons:
+     *
+     * When curl is used in a webserver application
+     * environment (cgi or php), this environment variable can
+     * be controlled by the web server user by setting the
+     * http header 'Proxy:' to some value.
+     *
+     * This can cause 'internal' http/ftp requests to be
+     * arbitrarily redirected by any external attacker.
+     */
+    if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) {
+      /* There was no lowercase variable, try the uppercase version: */
+      Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
       prox=curl_getenv(proxy_env);
+    }
 
-      /*
-       * We don't try the uppercase version of HTTP_PROXY because of
-       * security reasons:
-       *
-       * When curl is used in a webserver application
-       * environment (cgi or php), this environment variable can
-       * be controlled by the web server user by setting the
-       * http header 'Proxy:' to some value.
-       *
-       * This can cause 'internal' http/ftp requests to be
-       * arbitrarily redirected by any external attacker.
-       */
-      if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) {
-        /* There was no lowercase variable, try the uppercase version: */
-       Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
-        prox=curl_getenv(proxy_env);
-      }
-
-      if(prox && *prox) { /* don't count "" strings */
-        proxy = prox; /* use this */
-      }
-      else {
-        proxy = curl_getenv("all_proxy"); /* default proxy to use */
-        if(!proxy)
-          proxy=curl_getenv("ALL_PROXY");
-      }
-
-      if(proxy && *proxy) {
-        long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
-
-        if(conn->proxytype == CURLPROXY_HTTP) {
-          /* force this connection's protocol to become HTTP */
-          conn->protocol = PROT_HTTP | bits;
-          conn->bits.proxy = conn->bits.httpproxy = TRUE;
-        }
-      }
-    } /* if(!nope) - it wasn't specified non-proxy */
-  } /* NO_PROXY wasn't specified or '*' */
+    if(prox && *prox) { /* don't count "" strings */
+      proxy = prox; /* use this */
+    }
+    else {
+      proxy = curl_getenv("all_proxy"); /* default proxy to use */
+      if(!proxy)
+        proxy=curl_getenv("ALL_PROXY");
+    }
+  } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified
+       non-proxy */
   if(no_proxy)
     free(no_proxy);
 
@@ -3629,7 +3676,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
   char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
 
   if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
-    strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], MAX_CURL_USER_LENGTH);
+    strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
+            MAX_CURL_USER_LENGTH);
     proxyuser[MAX_CURL_USER_LENGTH-1] = '\0';   /*To be on safe side*/
   }
   if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
@@ -4117,15 +4165,26 @@ static CURLcode create_conn(struct SessionHandle *data,
                         and the SessionHandle */
 
   conn->proxytype = data->set.proxytype; /* type */
+
+#ifdef CURL_DISABLE_PROXY
+
+  conn->bits.proxy = FALSE;
+  conn->bits.httpproxy = FALSE;
+  conn->bits.proxy_user_passwd = FALSE;
+  conn->bits.tunnel_proxy = FALSE;
+
+#else /* CURL_DISABLE_PROXY */
+
   conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
                             *data->set.str[STRING_PROXY]);
   conn->bits.httpproxy = (bool)(conn->bits.proxy
                                 && (conn->proxytype == CURLPROXY_HTTP));
+  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]);
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
 
+#endif /* CURL_DISABLE_PROXY */
 
   conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]);
-  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]);
-  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
   conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
   conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
 
@@ -4205,11 +4264,34 @@ static CURLcode create_conn(struct SessionHandle *data,
 
   if(!proxy)
     proxy = detect_proxy(conn);
+  else if(data->set.str[STRING_NOPROXY]) {
+    if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) {
+      free(proxy);  /* proxy is in exception list */
+      proxy = NULL;
+    }
+  }
   if(proxy && !*proxy) {
     free(proxy);  /* Don't bother with an empty proxy string */
     proxy = NULL;
   }
   /* proxy must be freed later unless NULL */
+  if(proxy && *proxy) {
+    long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
+
+    if(conn->proxytype == CURLPROXY_HTTP) {
+      /* force this connection's protocol to become HTTP */
+      conn->protocol = PROT_HTTP | bits;
+      conn->bits.httpproxy = TRUE;
+    }
+    conn->bits.proxy = TRUE;
+  }
+  else {
+      /* we aren't using the proxy after all... */
+      conn->bits.proxy = FALSE;
+      conn->bits.httpproxy = FALSE;
+      conn->bits.proxy_user_passwd = FALSE;
+      conn->bits.tunnel_proxy = FALSE;
+  }
 #endif /* CURL_DISABLE_PROXY */
 
   /*************************************************************
index aa3d19feb85498a8e1b6324f0d3969ca2501f2d3..39d217c656ccf64651a6e3e6bb41d8361300aeb5 100644 (file)
@@ -1363,6 +1363,8 @@ enum dupstring {
   STRING_PASSWORD,        /* <password>, if used */
   STRING_PROXYUSERNAME,   /* Proxy <username>, if used */
   STRING_PROXYPASSWORD,   /* Proxy <password>, if used */
+  STRING_NOPROXY,         /* List of hosts which should not use the proxy, if
+                             used */
 
   /* -- end of strings -- */
   STRING_LAST /* not used, just an end-of-list marker */
index f8e53384dc8945031e1ff0fae12e05f73ef0f3d7..f99550dcf0211861a17c99014ba3b576a362e7c0 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2009, 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
@@ -448,6 +448,7 @@ struct Configurable {
   char *userpwd;
   char *proxyuserpwd;
   char *proxy;
+  char *noproxy;
   bool proxytunnel;
   bool ftp_append;         /* APPE on ftp */
   bool mute;               /* shutup */
@@ -772,6 +773,7 @@ static void help(void)
     " -N/--no-buffer     Disable buffering of the output stream",
     "    --no-keepalive  Disable keepalive use on the connection",
     "    --no-sessionid  Disable SSL session-ID reusing (SSL)",
+    "    --noproxy       Comma-separated list of hosts which do not use proxy",
     "    --ntlm          Use HTTP NTLM authentication (H)",
     " -o/--output <file> Write output to <file> instead of stdout",
     "    --pass  <pass>  Pass phrase for the private key (SSL/SSH)",
@@ -1666,6 +1668,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
     {"$2", "socks5-hostname", TRUE},
     {"$3", "keepalive-time",  TRUE},
     {"$4", "post302",    FALSE},
+    {"$5", "noproxy",    TRUE},
 
     {"0", "http1.0",     FALSE},
     {"1", "tlsv1",       FALSE},
@@ -2175,6 +2178,10 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
       case '4': /* --post302 */
         config->post302 = toggle;
         break;
+      case '5': /* --noproxy */
+        /* This specifies the noproxy list */
+        GetStr(&config->noproxy, nextarg);
+        break;
       }
       break;
     case '#': /* --progress-bar */
@@ -3641,6 +3648,8 @@ static void free_config_fields(struct Configurable *config)
     free(config->proxy);
   if(config->proxyuserpwd)
     free(config->proxyuserpwd);
+  if(config->noproxy)
+    free(config->noproxy);
   if(config->cookie)
     free(config->cookie);
   if(config->cookiefile)
@@ -4559,6 +4568,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
         my_setopt(curl, CURLOPT_USERPWD, config->userpwd);
         my_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
+        my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
         my_setopt(curl, CURLOPT_RANGE, config->range);
         my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
         my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);