Bläddra i källkod

2008-02-18 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Added --bt-min-crypto-level and --bt-require-crypto options.
	* src/OptionHandlerFactory.cc
	* src/MSEHandshake.cc
	* src/HelpItemFactory.cc
	* src/option_processing.cc
	* src/ReceiverMSEHandshakeCommand.cc
	* src/prefs.h
	* src/DefaultBtAnnounce.cc
	* src/InitiatorMSEHandshakeCommand.cc
	* src/usage_text.h
	* test/MSEHandshakeTest.cc
Tatsuhiro Tsujikawa 17 år sedan
förälder
incheckning
20cd2e5246

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2008-02-18  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Added --bt-min-crypto-level and --bt-require-crypto options.
+	* src/OptionHandlerFactory.cc
+	* src/MSEHandshake.cc
+	* src/HelpItemFactory.cc
+	* src/option_processing.cc
+	* src/ReceiverMSEHandshakeCommand.cc
+	* src/prefs.h
+	* src/DefaultBtAnnounce.cc
+	* src/InitiatorMSEHandshakeCommand.cc
+	* src/usage_text.h
+	* test/MSEHandshakeTest.cc
+
 2008-02-18  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Bump version number to 0.13.0b

+ 6 - 1
src/DefaultBtAnnounce.cc

@@ -51,6 +51,7 @@
 #include "BtRuntime.h"
 #include "PeerStorage.h"
 #include "Peer.h"
+#include "Option.h"
 
 namespace aria2 {
 
@@ -160,7 +161,11 @@ std::string DefaultBtAnnounce::getAnnounceUrl() {
     url += std::string("&")+"trackerid="+Util::torrentUrlencode((const unsigned char*)trackerId.c_str(),
 							   trackerId.size());
   }
-  url += "&supportcrypto=1";
+  if(option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) {
+    url += "&requirecrypto=1";
+  } else {
+    url += "&supportcrypto=1";
+  }
   return url;
 }
 

+ 10 - 0
src/HelpItemFactory.cc

@@ -351,6 +351,16 @@ TagContainerHandle HelpItemFactory::createHelpItems()
     item->addTag(TAG_BITTORRENT);
     tc->addItem(item);
   }
+  {
+    HelpItemHandle item = new HelpItem(PREF_BT_MIN_CRYPTO_LEVEL, TEXT_BT_MIN_CRYPTO_LEVEL, V_PLAIN);
+    item->addTag(TAG_BITTORRENT);
+    tc->addItem(item);
+  }
+  {
+    HelpItemHandle item = new HelpItem(PREF_BT_REQUIRE_CRYPTO, TEXT_BT_REQUIRE_CRYPTO, V_FALSE);
+    item->addTag(TAG_BITTORRENT);
+    tc->addItem(item);
+  }
 #endif // ENABLE_BITTORRENT
 #ifdef ENABLE_METALINK
   {

+ 26 - 9
src/InitiatorMSEHandshakeCommand.cc

@@ -145,17 +145,34 @@ bool InitiatorMSEHandshakeCommand::executeInternal() {
 
 bool InitiatorMSEHandshakeCommand::prepareForNextPeer(int32_t wait)
 {
-  // try legacy BitTorrent handshake if preference allows it.
-  // TODO preference is not created yet.
-  logger->info("CUID#%d - Retry using legacy BitTorrent handshake.", cuid);
-  Command* command =
-    new PeerInitiateConnectionCommand(cuid, _requestGroup, peer, e, btContext,
-				      false);
-  e->commands.push_back(command);
-  return true;
+  if(e->option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) {
+    logger->info("CUID#%d - Establishing connection using legacy BitTorrent handshake is disabled by preference.", cuid);
+    if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) {
+      SharedHandle<Peer> peer = peerStorage->getUnusedPeer();
+      peer->usedBy(CUIDCounterSingletonHolder::instance()->newID());
+      Command* command =
+	new PeerInitiateConnectionCommand(peer->usedBy(), _requestGroup, peer, e,
+					  btContext);
+      e->commands.push_back(command);
+    }
+    return true;
+  } else {
+    // try legacy BitTorrent handshake
+    logger->info("CUID#%d - Retry using legacy BitTorrent handshake.", cuid);
+    Command* command =
+      new PeerInitiateConnectionCommand(cuid, _requestGroup, peer, e, btContext,
+					false);
+    e->commands.push_back(command);
+    return true;
+  }
 }
 
-void InitiatorMSEHandshakeCommand::onAbort(Exception* ex) {}
+void InitiatorMSEHandshakeCommand::onAbort(Exception* ex)
+{
+  if(e->option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) {
+    peerStorage->returnPeer(peer);
+  }
+}
 
 bool InitiatorMSEHandshakeCommand::exitBeforeExecute()
 {

+ 14 - 5
src/MSEHandshake.cc

@@ -48,6 +48,8 @@
 #include "Util.h"
 #include "BtRegistry.h"
 #include "BtContext.h"
+#include "prefs.h"
+#include "Option.h"
 #include <cstring>
 #include <cassert>
 
@@ -256,7 +258,10 @@ void MSEHandshake::sendInitiatorStep2()
     // crypto_provide
     unsigned char cryptoProvide[4];
     memset(cryptoProvide, 0, sizeof(cryptoProvide));
-    cryptoProvide[3] = CRYPTO_PLAIN_TEXT | CRYPTO_ARC4;
+    if(_option->get(PREF_BT_MIN_CRYPTO_LEVEL) == V_PLAIN) {
+      cryptoProvide[3] = CRYPTO_PLAIN_TEXT;
+    }
+    cryptoProvide[3] |= CRYPTO_ARC4;
     memcpy(buffer+8, cryptoProvide, sizeof(cryptoProvide));
 
     // len(padC)
@@ -328,7 +333,8 @@ bool MSEHandshake::receiveInitiatorCryptoSelectAndPadDLength()
     unsigned char cryptoSelect[CRYPTO_BITFIELD_LENGTH];
     _decryptor->decrypt(cryptoSelect, sizeof(cryptoSelect),
 			 rbufptr, sizeof(cryptoSelect));
-    if(cryptoSelect[3]&CRYPTO_PLAIN_TEXT) {
+    if(cryptoSelect[3]&CRYPTO_PLAIN_TEXT &&
+       _option->get(PREF_BT_MIN_CRYPTO_LEVEL) == V_PLAIN) {
       _logger->debug("CUID#%d - peer prefers plaintext.", _cuid);
       _negotiatedCryptoType = CRYPTO_PLAIN_TEXT;
     }
@@ -440,11 +446,11 @@ bool MSEHandshake::receiveReceiverHashAndPadCLength()
 			 rbufptr, sizeof(cryptoProvide));
     // TODO choose the crypto type based on the preference.
     // For now, choose ARC4.
-    if(cryptoProvide[3]&CRYPTO_PLAIN_TEXT) {
+    if(cryptoProvide[3]&CRYPTO_PLAIN_TEXT &&
+       _option->get(PREF_BT_MIN_CRYPTO_LEVEL) == V_PLAIN) {
       _logger->debug("CUID#%d - peer provides plaintext.", _cuid);
       _negotiatedCryptoType = CRYPTO_PLAIN_TEXT;
-    }
-    if(cryptoProvide[3]&CRYPTO_ARC4) {
+    } else if(cryptoProvide[3]&CRYPTO_ARC4) {
       _logger->debug("CUID#%d - peer provides ARC4.", _cuid);
       _negotiatedCryptoType = CRYPTO_ARC4;
     }
@@ -476,6 +482,9 @@ bool MSEHandshake::receiveReceiverIALength()
 
 bool MSEHandshake::receiveReceiverIA()
 {
+  if(_iaLength == 0) {
+    return true;
+  }
   int32_t r = _iaLength-_rbufLength;
   if(r > receiveNBytes(r)) {
     return false;

+ 2 - 0
src/OptionHandlerFactory.cc

@@ -119,6 +119,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 					       PREF_DHT_ENTRY_POINT_HOST,
 					       PREF_DHT_ENTRY_POINT_PORT));
   handlers.push_back(new NumberOptionHandler(PREF_STOP, 0, 35000000));
+  handlers.push_back(new ParameterOptionHandler(PREF_BT_MIN_CRYPTO_LEVEL, V_PLAIN, V_ARC4));
+  handlers.push_back(new BooleanOptionHandler(PREF_BT_REQUIRE_CRYPTO));
   
   return handlers;
 }

+ 3 - 0
src/ReceiverMSEHandshakeCommand.cc

@@ -86,6 +86,9 @@ bool ReceiverMSEHandshakeCommand::executeInternal()
       _sequence = RECEIVER_WAIT_KEY;
       break;
     case MSEHandshake::HANDSHAKE_LEGACY: {
+      if(e->option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) {
+	throw new DlAbortEx("The legacy BitTorrent handshake is not acceptable by the preference.");
+      }
       Command* c = new PeerReceiveHandshakeCommand(cuid, peer, e, socket);
       e->commands.push_back(c);
       return true;

+ 10 - 0
src/option_processing.cc

@@ -140,6 +140,8 @@ Option* option_processing(int argc, char* const argv[])
   op->put(PREF_ENABLE_DHT, V_FALSE);
   op->put(PREF_DHT_LISTEN_PORT, "6881-6999");
   op->put(PREF_DHT_FILE_PATH, Util::getHomeDir()+"/.aria2/dht.dat");
+  op->put(PREF_BT_MIN_CRYPTO_LEVEL, V_PLAIN);
+  op->put(PREF_BT_REQUIRE_CRYPTO, V_FALSE);
 
   // following options are not parsed by OptionHandler and not stored in Option.
   bool noConf = false;
@@ -221,6 +223,8 @@ Option* option_processing(int argc, char* const argv[])
       { "enable-dht", optional_argument, &lopt, 27 },
       { "dht-listen-port", required_argument, &lopt, 28 },
       { "dht-entry-point", required_argument, &lopt, 29 },
+      { PREF_BT_MIN_CRYPTO_LEVEL, required_argument, &lopt, 30 },
+      { PREF_BT_REQUIRE_CRYPTO, required_argument, &lopt, 31 },
 #endif // ENABLE_BITTORRENT
 #ifdef ENABLE_METALINK
       { "metalink-file", required_argument, NULL, 'M' },
@@ -325,6 +329,12 @@ Option* option_processing(int argc, char* const argv[])
       case 29:
 	cmdstream << PREF_DHT_ENTRY_POINT << "=" << optarg << "\n";
 	break;
+      case 30:
+	cmdstream << PREF_BT_MIN_CRYPTO_LEVEL << "=" << optarg << "\n";
+	break;
+      case 31:
+	cmdstream << PREF_BT_REQUIRE_CRYPTO << "=" << optarg << "\n";
+	break;
       case 100:
 	cmdstream << PREF_METALINK_VERSION << "=" << optarg << "\n";
 	break;

+ 6 - 0
src/prefs.h

@@ -228,6 +228,12 @@
 #define PREF_DHT_ENTRY_POINT "dht-entry-point"
 // values: a string
 #define PREF_DHT_FILE_PATH "dht-file-path"
+// values: plain | arc4
+#define PREF_BT_MIN_CRYPTO_LEVEL "bt-min-crypto-level"
+#  define V_PLAIN "plain"
+#  define V_ARC4 "arc4"
+// values:: true | false
+#define PREF_BT_REQUIRE_CRYPTO "bt-require-crypto"
 
 /**
  * Metalink related preferences

+ 9 - 0
src/usage_text.h

@@ -267,6 +267,15 @@ _(" --dht-listen-port...         Set UDP listening port for DHT.\n"\
 #define TEXT_DHT_ENTRY_POINT \
 _(" --dht-entry-point=HOST:PORT  Set host and port as an entry point to DHT\n"\
   "                              network.")
+#define TEXT_BT_MIN_CRYPTO_LEVEL \
+_(" --bt-min-crypto-level=plain|arc4 Set minimum level of encryption method.\n"\
+  "                              If several encryption methods are provided by a\n"\
+  "                              peer, aria2 chooses a lowest one which satisfies\n"\
+  "                              given level.")
+#define TEXT_BT_REQUIRE_CRYPTO \
+_(" --bt-require-crypto=true|false If true is given, aria2 doesn't accept and\n"\
+  "                              establish connection with legacy BitTorrent\n"\
+  "                              handshake. Thus always use Obfuscation handshake.")
 #define TEXT_METALINK_FILE \
 _(" -M, --metalink-file=METALINK_FILE The file path to the .metalink file.")
 #define TEXT_METALINK_SERVERS \

+ 127 - 0
test/MSEHandshakeTest.cc

@@ -0,0 +1,127 @@
+#include "MSEHandshake.h"
+#include "Exception.h"
+#include "Util.h"
+#include "prefs.h"
+#include "Socket.h"
+#include "Option.h"
+#include "BtRegistry.h"
+#include "MockBtContext.h"
+#include "FileEntry.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace aria2 {
+
+class MSEHandshakeTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(MSEHandshakeTest);
+  CPPUNIT_TEST(testHandshake);
+  CPPUNIT_TEST_SUITE_END();
+private:
+  SharedHandle<MockBtContext> _btctx;
+
+  void doHandshake(const SharedHandle<MSEHandshake>& initiator,
+		   const SharedHandle<MSEHandshake>& receiver);
+
+public:
+  void setUp()
+  {
+    _btctx = new MockBtContext();
+    unsigned char infoHash[20];
+    memset(infoHash, 0, sizeof(infoHash));
+    _btctx->setInfoHash(infoHash);
+
+    BtRegistry::unregisterAll();
+    BtRegistry::registerBtContext(_btctx->getInfoHashAsString(), _btctx);
+  }
+
+  void tearDown()
+  {
+    BtRegistry::unregisterAll();
+  }
+
+  void testHandshake();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MSEHandshakeTest);
+
+static std::pair<SocketCore*, SocketCore*> createSocketPair()
+{
+  SocketCore* initiatorSock = new SocketCore();
+
+  SocketCore receiverServerSock;
+  receiverServerSock.bind(0);
+  receiverServerSock.beginListen();
+
+  std::pair<std::string, int32_t> receiverAddrInfo;
+  receiverServerSock.getAddrInfo(receiverAddrInfo);
+  initiatorSock->establishConnection("127.0.0.1", receiverAddrInfo.second);
+  initiatorSock->setBlockingMode();
+
+  SocketCore* receiverSock = receiverServerSock.acceptConnection();
+  receiverSock->setBlockingMode();
+
+  return std::pair<SocketCore*, SocketCore*>(initiatorSock, receiverSock);
+}
+
+void MSEHandshakeTest::doHandshake(const SharedHandle<MSEHandshake>& initiator, const SharedHandle<MSEHandshake>& receiver)
+{
+  initiator->sendPublicKey();
+
+  while(!receiver->receivePublicKey());
+  receiver->sendPublicKey();
+
+  while(!initiator->receivePublicKey());
+  initiator->initCipher(_btctx->getInfoHash());
+  initiator->sendInitiatorStep2();
+
+  while(!receiver->findReceiverHashMarker());
+  while(!receiver->receiveReceiverHashAndPadCLength());
+  while(!receiver->receivePad());
+  while(!receiver->receiveReceiverIALength());
+  while(!receiver->receiveReceiverIA());
+  receiver->sendReceiverStep2();
+
+  while(!initiator->findInitiatorVCMarker());
+  while(!initiator->receiveInitiatorCryptoSelectAndPadDLength());
+  while(!initiator->receivePad());
+}
+
+static MSEHandshake* createMSEHandshake(SocketCore* socket, bool initiator, const Option* option)
+{
+  MSEHandshake* h = new MSEHandshake(1, socket, option);
+  h->initEncryptionFacility(initiator);
+  return h;
+}
+
+void MSEHandshakeTest::testHandshake()
+{
+  {
+    Option op;
+    op.put(PREF_BT_MIN_CRYPTO_LEVEL, V_PLAIN);
+
+    std::pair<SocketCore*, SocketCore*> sockPair = createSocketPair();
+    SharedHandle<MSEHandshake> initiator = createMSEHandshake(sockPair.first, true, &op);
+    SharedHandle<MSEHandshake> receiver = createMSEHandshake(sockPair.second, false, &op);
+
+    doHandshake(initiator, receiver);
+
+    CPPUNIT_ASSERT_EQUAL(MSEHandshake::CRYPTO_PLAIN_TEXT, initiator->getNegotiatedCryptoType());
+    CPPUNIT_ASSERT_EQUAL(MSEHandshake::CRYPTO_PLAIN_TEXT, receiver->getNegotiatedCryptoType());
+  }
+  {
+    Option op;
+    op.put(PREF_BT_MIN_CRYPTO_LEVEL, V_ARC4);
+
+    std::pair<SocketCore*, SocketCore*> sockPair = createSocketPair();
+    SharedHandle<MSEHandshake> initiator = createMSEHandshake(sockPair.first, true, &op);
+    SharedHandle<MSEHandshake> receiver = createMSEHandshake(sockPair.second, false, &op);
+
+    doHandshake(initiator, receiver);
+
+    CPPUNIT_ASSERT_EQUAL(MSEHandshake::CRYPTO_ARC4, initiator->getNegotiatedCryptoType());
+    CPPUNIT_ASSERT_EQUAL(MSEHandshake::CRYPTO_ARC4, receiver->getNegotiatedCryptoType());
+  }
+}
+
+} // namespace aria2

+ 2 - 1
test/Makefile.am

@@ -130,7 +130,8 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\
 	DHTRoutingTableSerializerTest.cc\
 	DHTRoutingTableDeserializerTest.cc\
 	DHKeyExchangeTest.cc\
-	ARC4Test.cc
+	ARC4Test.cc\
+	MSEHandshakeTest.cc
 endif # ENABLE_BITTORRENT
 
 if ENABLE_METALINK

+ 7 - 4
test/Makefile.in

@@ -115,7 +115,8 @@ check_PROGRAMS = $(am__EXEEXT_1)
 @ENABLE_BITTORRENT_TRUE@	DHTRoutingTableSerializerTest.cc\
 @ENABLE_BITTORRENT_TRUE@	DHTRoutingTableDeserializerTest.cc\
 @ENABLE_BITTORRENT_TRUE@	DHKeyExchangeTest.cc\
-@ENABLE_BITTORRENT_TRUE@	ARC4Test.cc
+@ENABLE_BITTORRENT_TRUE@	ARC4Test.cc\
+@ENABLE_BITTORRENT_TRUE@	MSEHandshakeTest.cc
 
 @ENABLE_METALINK_TRUE@am__append_3 = MetalinkerTest.cc\
 @ENABLE_METALINK_TRUE@	MetalinkEntryTest.cc\
@@ -210,8 +211,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc SocketCoreTest.cc \
 	DHTTokenTrackerTest.cc XORCloserTest.cc DHTIDCloserTest.cc \
 	DHTRoutingTableSerializerTest.cc \
 	DHTRoutingTableDeserializerTest.cc DHKeyExchangeTest.cc \
-	ARC4Test.cc MetalinkerTest.cc MetalinkEntryTest.cc \
-	Metalink2RequestGroupTest.cc \
+	ARC4Test.cc MSEHandshakeTest.cc MetalinkerTest.cc \
+	MetalinkEntryTest.cc Metalink2RequestGroupTest.cc \
 	MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc \
 	MetalinkParserControllerTest.cc MetalinkProcessorTest.cc
 @ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 =  \
@@ -289,7 +290,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc SocketCoreTest.cc \
 @ENABLE_BITTORRENT_TRUE@	DHTRoutingTableSerializerTest.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DHTRoutingTableDeserializerTest.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DHKeyExchangeTest.$(OBJEXT) \
-@ENABLE_BITTORRENT_TRUE@	ARC4Test.$(OBJEXT)
+@ENABLE_BITTORRENT_TRUE@	ARC4Test.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	MSEHandshakeTest.$(OBJEXT)
 @ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkEntryTest.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	Metalink2RequestGroupTest.$(OBJEXT) \
@@ -710,6 +712,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChecksumValidatorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChunkChecksumValidatorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ListTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshakeTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelperTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroupTest.Po@am__quote@