浏览代码

2010-03-19 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Accept IPv4 network address with CIDR block in --no-proxy option
	and no_proxy environment variable.  Current implementation does
	not resolve hostname in URI to compare network address. So it is
	only effecive if URI has numeric IP addresses.
	* doc/aria2c.1.txt
	* src/AbstractCommand.cc
	* src/OptionHandlerFactory.cc
	* src/bitfield.h
	* src/usage_text.h
	* src/util.cc
	* src/util.h
	* test/UtilTest.cc
	* test/bitfieldTest.cc
Tatsuhiro Tsujikawa 15 年之前
父节点
当前提交
4951142346
共有 12 个文件被更改,包括 211 次插入30 次删除
  1. 16 0
      ChangeLog
  2. 32 6
      doc/aria2c.1
  3. 27 9
      doc/aria2c.1.html
  4. 22 9
      doc/aria2c.1.txt
  5. 27 3
      src/AbstractCommand.cc
  6. 3 1
      src/OptionHandlerFactory.cc
  7. 5 1
      src/bitfield.h
  8. 2 1
      src/usage_text.h
  9. 34 0
      src/util.cc
  10. 7 0
      src/util.h
  11. 34 0
      test/UtilTest.cc
  12. 2 0
      test/bitfieldTest.cc

+ 16 - 0
ChangeLog

@@ -1,3 +1,19 @@
+2010-03-19  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Accept IPv4 network address with CIDR block in --no-proxy option
+	and no_proxy environment variable.  Current implementation does
+	not resolve hostname in URI to compare network address. So it is
+	only effecive if URI has numeric IP addresses.
+	* doc/aria2c.1.txt
+	* src/AbstractCommand.cc
+	* src/OptionHandlerFactory.cc
+	* src/bitfield.h
+	* src/usage_text.h
+	* src/util.cc
+	* src/util.h
+	* test/UtilTest.cc
+	* test/bitfieldTest.cc
+
 2010-03-19  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Reduced interval for metadatagetmode to quickly gather metadata.

+ 32 - 6
doc/aria2c.1

@@ -2,12 +2,12 @@
 .\"     Title: aria2c
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 03/13/2010
+.\"      Date: 03/19/2010
 .\"    Manual: Aria2 Manual
-.\"    Source: Aria2 1.9.0
+.\"    Source: Aria2 1.9.1a
 .\"  Language: English
 .\"
-.TH "ARIA2C" "1" "03/13/2010" "Aria2 1\&.9\&.0" "Aria2 Manual"
+.TH "ARIA2C" "1" "03/19/2010" "Aria2 1\&.9\&.1a" "Aria2 Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -197,7 +197,23 @@ Disables netrc support\&. netrc support is enabled by default\&.
 .PP
 \fB\-\-no\-proxy\fR=DOMAINS
 .RS 4
-Specify comma separated hostnames or domains where proxy should not be used\&.
+Specify comma separated hostnames, domains and network address with or without CIDR block where proxy should not be used\&.
+.RE
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
+.sp
+For network address with CIDR block, only IPv4 address works\&. Current implementation does not resolve hostname in URI to compare network address specified in \fB\-\-no\-proxy\fR\&. So it is only effecive if URI has numeric IP addresses\&.
+.sp .5v
 .RE
 .PP
 \fB\-o\fR, \fB\-\-out\fR=FILE
@@ -1369,7 +1385,7 @@ overrides this value\&.
 .PP
 no_proxy [DOMAIN,\&...]
 .RS 4
-Specify comma\-separated hostname or domains to which proxy should not be used\&. Overrides no\-proxy value in configuration file\&. The command\-line option
+Specify comma\-separated hostname, domains and network address with or without CIDR block to which proxy should not be used\&. Overrides no\-proxy value in configuration file\&. The command\-line option
 \fB\-\-no\-proxy\fR
 overrides this value\&.
 .RE
@@ -3030,6 +3046,16 @@ aria2c \-\-http\-proxy="http://proxy:8080" "http://host/file"
 .RE
 .\}
 .sp
+.if n \{\
+.RS 4
+.\}
+.nf
+aria2c \-\-http\-proxy="http://proxy:8080" \-\-no\-proxy="localhost,127\&.0\&.0\&.1,192\&.168\&.0\&.0/16" "http://host/file"
+.fi
+.if n \{\
+.RE
+.\}
+.sp
 For FTP:
 .sp
 .if n \{\
@@ -3054,7 +3080,7 @@ aria2c \-\-ftp\-proxy="http://proxy:8080" "ftp://host/file"
 .ps -1
 .br
 .sp
-See \fB\-\-http\-proxy\fR, \fB\-\-https\-proxy\fR, \fB\-\-ftp\-proxy\fR and \fB\-\-all\-proxy\fR for details\&. You can specify proxy in the environment variables\&. See \fBENVIRONMENT\fR section\&.
+See \fB\-\-http\-proxy\fR, \fB\-\-https\-proxy\fR, \fB\-\-ftp\-proxy\fR, \fB\-\-all\-proxy\fR and \fB\-\-no\-proxy\fR for details\&. You can specify proxy in the environment variables\&. See \fBENVIRONMENT\fR section\&.
 .sp .5v
 .RE
 .RE

+ 27 - 9
doc/aria2c.1.html

@@ -793,10 +793,23 @@ then you get HTTP proxy "http://proxy" with user "user" and password
 </dt>
 <dd>
 <p>
-  Specify comma separated hostnames or domains where proxy should not be
-  used.
+  Specify comma separated hostnames, domains and network address with
+  or without CIDR block where proxy should not be used.
 </p>
 </dd>
+</dl></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">For network address with CIDR block, only IPv4 address works.  Current
+implementation does not resolve hostname in URI to compare network
+address specified in <strong>--no-proxy</strong>. So it is only effecive if URI has
+numeric IP addresses.</td>
+</tr></table>
+</div>
+<div class="dlist"><dl>
 <dt class="hdlist1">
 <strong>-o</strong>, <strong>--out</strong>=FILE
 </dt>
@@ -2281,9 +2294,10 @@ no_proxy [DOMAIN,&#8230;]
 </dt>
 <dd>
 <p>
-  Specify comma-separated hostname or domains to which proxy should not be used.
-  Overrides no-proxy value in configuration file.
-  The command-line option <strong>--no-proxy</strong> overrides this value.
+  Specify comma-separated hostname, domains and network address with
+  or without CIDR block to which proxy should not be used.  Overrides
+  no-proxy value in configuration file.  The command-line option
+  <strong>--no-proxy</strong> overrides this value.
 </p>
 </dd>
 </dl></div>
@@ -3621,6 +3635,10 @@ pprint(r)</tt></pre>
 <div class="content">
 <pre><tt>aria2c --http-proxy="http://proxy:8080" "http://host/file"</tt></pre>
 </div></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt>aria2c --http-proxy="http://proxy:8080" --no-proxy="localhost,127.0.0.1,192.168.0.0/16" "http://host/file"</tt></pre>
+</div></div>
 <div class="paragraph"><p>For FTP:</p></div>
 <div class="listingblock">
 <div class="content">
@@ -3631,9 +3649,9 @@ pprint(r)</tt></pre>
 <td class="icon">
 <div class="title">Note</div>
 </td>
-<td class="content">See <strong>--http-proxy</strong>, <strong>--https-proxy</strong>, <strong>--ftp-proxy</strong> and <strong>--all-proxy</strong> for
-details.
-You can specify proxy in the environment variables. See <strong>ENVIRONMENT</strong> section.</td>
+<td class="content">See <strong>--http-proxy</strong>, <strong>--https-proxy</strong>, <strong>--ftp-proxy</strong>, <strong>--all-proxy</strong> and
+<strong>--no-proxy</strong> for details.  You can specify proxy in the environment
+variables. See <strong>ENVIRONMENT</strong> section.</td>
 </tr></table>
 </div>
 <h4 id="_proxy_with_authorization">Proxy with authorization</h4>
@@ -3965,7 +3983,7 @@ files in the program, then also delete it here.</p></div>
 <div id="footnotes"><hr /></div>
 <div id="footer">
 <div id="footer-text">
-Last updated 2010-03-13 00:35:15 JST
+Last updated 2010-03-19 17:37:54 JST
 </div>
 </div>
 </body>

+ 22 - 9
doc/aria2c.1.txt

@@ -3,7 +3,7 @@ ARIA2C(1)
 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
 :man source: Aria2
 :man manual: Aria2 Manual
-:man version: 1.9.0
+:man version: 1.9.1a
 
 NAME
 ----
@@ -144,8 +144,14 @@ then you get HTTP proxy "http://proxy" with user "user" and password
   Disables netrc support. netrc support is enabled by default.
 
 *--no-proxy*=DOMAINS::
-  Specify comma separated hostnames or domains where proxy should not be
-  used.
+  Specify comma separated hostnames, domains and network address with
+  or without CIDR block where proxy should not be used.
+
+[NOTE]
+For network address with CIDR block, only IPv4 address works.  Current
+implementation does not resolve hostname in URI to compare network
+address specified in *--no-proxy*. So it is only effecive if URI has
+numeric IP addresses.
 
 *-o*, *--out*=FILE::
 
@@ -973,9 +979,11 @@ all_proxy [\http://][USER:PASSWORD@]HOST[:PORT]::
   The command-line option *--all-proxy* overrides this value.
 
 no_proxy [DOMAIN,...]::
-  Specify comma-separated hostname or domains to which proxy should not be used.
-  Overrides no-proxy value in configuration file.
-  The command-line option *--no-proxy* overrides this value.
+
+  Specify comma-separated hostname, domains and network address with
+  or without CIDR block to which proxy should not be used.  Overrides
+  no-proxy value in configuration file.  The command-line option
+  *--no-proxy* overrides this value.
 
 FILES
 -----
@@ -1798,15 +1806,20 @@ For HTTP:
 ----------------------------------------------------------
 aria2c --http-proxy="http://proxy:8080" "http://host/file"
 ----------------------------------------------------------
+----------------------------------------------------------
+aria2c --http-proxy="http://proxy:8080" --no-proxy="localhost,127.0.0.1,192.168.0.0/16" "http://host/file"
+----------------------------------------------------------
+
 For FTP:
 --------------------------------------------------------
 aria2c --ftp-proxy="http://proxy:8080" "ftp://host/file"
 --------------------------------------------------------
 
 [NOTE]
-See *--http-proxy*, *--https-proxy*, *--ftp-proxy* and *--all-proxy* for
-details.
-You can specify proxy in the environment variables. See *ENVIRONMENT* section.
+
+See *--http-proxy*, *--https-proxy*, *--ftp-proxy*, *--all-proxy* and
+*--no-proxy* for details.  You can specify proxy in the environment
+variables. See *ENVIRONMENT* section.
 
 Proxy with authorization
 ^^^^^^^^^^^^^^^^^^^^^^^^

+ 27 - 3
src/AbstractCommand.cc

@@ -448,9 +448,33 @@ static bool inNoProxy(const SharedHandle<Request>& req,
   if(entries.empty()) {
     return false;
   }
-  return
-    std::find_if(entries.begin(), entries.end(),
-                 DomainMatch(A2STR::DOT_C+req->getHost())) != entries.end();
+  DomainMatch domainMatch(A2STR::DOT_C+req->getHost());
+  for(std::vector<std::string>::const_iterator i = entries.begin(),
+        eoi = entries.end(); i != eoi; ++i) {
+    std::string::size_type slashpos = (*i).find('/');
+    if(slashpos == std::string::npos) {
+      if(domainMatch(*i)) {
+        return true;
+      }
+    } else {
+      if(!util::isNumericHost(req->getHost())) {
+        // TODO We don't resolve hostname here.  More complete
+        // implementation is that we should first resolve
+        // hostname(which may result in several IP addresses) and
+        // evaluates against all of them
+        continue;
+      }
+      std::string ip = (*i).substr(0, slashpos);
+      uint32_t bits;
+      if(!util::parseUIntNoThrow(bits, (*i).substr(slashpos+1))) {
+        continue;
+      }
+      if(util::inSameCidrBlock(ip, req->getHost(), bits)) {
+        return true;
+      }
+    }
+  }
+  return false;
 }
 
 bool AbstractCommand::isProxyDefined() const

+ 3 - 1
src/OptionHandlerFactory.cc

@@ -971,7 +971,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
                                    (PREF_NO_PROXY,
-                                    TEXT_NO_PROXY));
+                                    TEXT_NO_PROXY,
+                                    NO_DEFAULT_VALUE,
+                                    "HOSTNAME,DOMAIN,NETWORK/CIDR"));
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     op->addTag(TAG_HTTPS);

+ 5 - 1
src/bitfield.h

@@ -51,7 +51,11 @@ namespace bitfield {
 // then 0x80 is returned. nbits = 12, then 0xf0 is returned.
 inline unsigned char lastByteMask(size_t nbits)
 {
-  return -256 >> (8-((nbits+7)/8*8-nbits));
+  if(nbits == 0) {
+    return 0;
+  } else {
+    return -256 >> (8-((nbits+7)/8*8-nbits));
+  }
 }
 
 // Returns true if index-th bits is set. Otherwise returns false.

+ 2 - 1
src/usage_text.h

@@ -480,7 +480,8 @@
   _(" --check-certificate[=true|false] Verify the peer using certificates specified\n" \
     "                              in --ca-certificate option.")
 #define TEXT_NO_PROXY                                                   \
-  _(" --no-proxy=DOMAINS           Specify comma separated hostnames or domains where\n" \
+  _(" --no-proxy=DOMAINS           Specify comma separated hostnames, domains or\n" \
+    "                              network address with or without CIDR block where\n" \
     "                              proxy should not be used.")
 #define TEXT_USE_HEAD                                                   \
   _(" --use-head[=true|false]      Use HEAD method for the first request to the HTTP\n" \

+ 34 - 0
src/util.cc

@@ -75,6 +75,7 @@
 #include "A2STR.h"
 #include "array_fun.h"
 #include "a2functional.h"
+#include "bitfield.h"
 #ifdef ENABLE_MESSAGE_DIGEST
 # include "MessageDigestHelper.h"
 #endif // ENABLE_MESSAGE_DIGEST
@@ -1263,6 +1264,39 @@ std::string escapePath(const std::string& s)
   return d;
 }
 
+bool getCidrPrefix(struct in_addr& in, const std::string& ip, int bits)
+{
+  struct in_addr t;
+  if(inet_aton(ip.c_str(), &t) == 0) {
+    return false;
+  }
+  int lastindex = bits/8;
+  if(lastindex < 4) {
+    char* p = reinterpret_cast<char*>(&t.s_addr);
+    const char* last = p+4;
+    p += lastindex;    
+    if(bits%8 != 0) {
+      *p &= bitfield::lastByteMask(bits);
+      ++p;
+    }
+    for(; p != last; ++p) {
+      *p &= 0;
+    }
+  }
+  in = t;
+  return true;
+}
+
+bool inSameCidrBlock(const std::string& ip1, const std::string& ip2, int bits)
+{
+  struct in_addr in1;
+  struct in_addr in2;
+  if(!getCidrPrefix(in1, ip1, bits) || !getCidrPrefix(in2, ip2, bits)) {
+    return false;
+  }
+  return in1.s_addr == in2.s_addr;
+}
+
 } // namespace util
 
 } // namespace aria2

+ 7 - 0
src/util.h

@@ -382,6 +382,13 @@ bool detectDirTraversal(const std::string& s);
 // '_': '"', '*', ':', '<', '>', '?', '\', '|'.
 std::string escapePath(const std::string& s);
 
+// Stores network address of numeric IPv4 address ip using CIDR bits
+// into in.  On success, returns true. Otherwise returns false.
+bool getCidrPrefix(struct in_addr& in, const std::string& ip, int bits);
+
+// Returns true if ip1 and ip2 are in the same CIDR block.
+bool inSameCidrBlock(const std::string& ip1, const std::string& ip2, int bits);
+
 } // namespace util
 
 } // namespace aria2

+ 34 - 0
test/UtilTest.cc

@@ -63,6 +63,8 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testIsNumericHost);
   CPPUNIT_TEST(testDetectDirTraversal);
   CPPUNIT_TEST(testEscapePath);
+  CPPUNIT_TEST(testGetCidrPrefix);
+  CPPUNIT_TEST(testInSameCidrBlock);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -114,6 +116,8 @@ public:
   void testIsNumericHost();
   void testDetectDirTraversal();
   void testEscapePath();
+  void testGetCidrPrefix();
+  void testInSameCidrBlock();
 };
 
 
@@ -1064,4 +1068,34 @@ void UtilTest::testEscapePath()
 #endif // !__MINGW32__
 }
 
+void UtilTest::testGetCidrPrefix()
+{
+  struct in_addr in;
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "192.168.0.1", 16));
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.0"), std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "192.168.255.255", 17));
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.128.0"),std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "192.168.128.1", 16));
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.0"), std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "192.168.0.1", 32));
+  CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "192.168.0.1", 0));
+  CPPUNIT_ASSERT_EQUAL(std::string("0.0.0.0"), std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(util::getCidrPrefix(in, "10.10.1.44", 27));
+  CPPUNIT_ASSERT_EQUAL(std::string("10.10.1.32"), std::string(inet_ntoa(in)));
+
+  CPPUNIT_ASSERT(!util::getCidrPrefix(in, "::1", 32));
+}
+
+void UtilTest::testInSameCidrBlock()
+{
+  CPPUNIT_ASSERT(util::inSameCidrBlock("192.168.128.1", "192.168.0.1", 16));
+  CPPUNIT_ASSERT(!util::inSameCidrBlock("192.168.128.1", "192.168.0.1", 17));
+}
+
 } // namespace aria2

+ 2 - 0
test/bitfieldTest.cc

@@ -56,6 +56,8 @@ void bitfieldTest::testCountSetBit()
 
 void bitfieldTest::testLastByteMask()
 {
+  CPPUNIT_ASSERT_EQUAL((unsigned int)0,
+                       (unsigned int)bitfield::lastByteMask(0));
   CPPUNIT_ASSERT_EQUAL((unsigned int)128,
                        (unsigned int)bitfield::lastByteMask(9));
   CPPUNIT_ASSERT_EQUAL((unsigned int)240,