/**
   * Verify: Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's new relay tag + Bob's
   * signed on time Caller must synch on this.
   */
  private boolean verifySessionCreated() {
    byte signed[] =
        new byte
            [256
                + 256 // X + Y
                + _aliceIP.length
                + 2
                + _bobIP.length
                + 2
                + 4 // sent relay tag
                + 4 // signed on time
            ];

    int off = 0;
    System.arraycopy(_sentX, 0, signed, off, _sentX.length);
    off += _sentX.length;
    System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
    off += _receivedY.length;
    System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
    off += _aliceIP.length;
    DataHelper.toLong(signed, off, 2, _alicePort);
    off += 2;
    System.arraycopy(_bobIP, 0, signed, off, _bobIP.length);
    off += _bobIP.length;
    DataHelper.toLong(signed, off, 2, _bobPort);
    off += 2;
    DataHelper.toLong(signed, off, 4, _receivedRelayTag);
    off += 4;
    DataHelper.toLong(signed, off, 4, _receivedSignedOnTime);
    boolean valid =
        _context
            .dsa()
            .verifySignature(_receivedSignature, signed, _remotePeer.getSigningPublicKey());
    if (_log.shouldLog(Log.DEBUG) || (_log.shouldLog(Log.WARN) && !valid)) {
      StringBuilder buf = new StringBuilder(128);
      buf.append("Signed sessionCreated:");
      buf.append(" Alice: ").append(Addresses.toString(_aliceIP, _alicePort));
      buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort));
      buf.append(" RelayTag: ").append(_receivedRelayTag);
      buf.append(" SignedOn: ").append(_receivedSignedOnTime);
      buf.append(" signature: ").append(Base64.encode(_receivedSignature.getData()));
      if (valid) _log.debug(buf.toString());
      else if (_log.shouldLog(Log.WARN)) _log.warn("INVALID: " + buf.toString());
    }
    return valid;
  }
Beispiel #2
0
 /**
  * Caching version of InetAddress.getByName(getOption("host")).getAddress(), which is slow. Caches
  * numeric host names only. Will resolve but not cache resolution of DNS host names.
  *
  * @return IP or null
  * @since 0.9.3
  */
 public byte[] getIP() {
   if (_ip != null) return _ip;
   byte[] rv = null;
   String host = getHost();
   if (host != null) {
     rv = Addresses.getIP(host);
     if (rv != null
         && (host.replaceAll("[0-9\\.]", "").length() == 0
             || host.replaceAll("[0-9a-fA-F:]", "").length() == 0)) {
       _ip = rv;
     }
   }
   return rv;
 }
  public synchronized void receiveSessionCreated(UDPPacketReader.SessionCreatedReader reader) {
    if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) {
      if (_log.shouldLog(Log.WARN)) _log.warn("Session created already failed");
      return;
    }
    if (_receivedY != null) {
      if (_log.shouldLog(Log.DEBUG)) _log.debug("Session created already received, ignoring");
      return; // already received
    }
    _receivedY = new byte[UDPPacketReader.SessionCreatedReader.Y_LENGTH];
    reader.readY(_receivedY, 0);
    if (_aliceIP == null) _aliceIP = new byte[reader.readIPSize()];
    reader.readIP(_aliceIP, 0);
    _alicePort = reader.readPort();
    _receivedRelayTag = reader.readRelayTag();
    _receivedSignedOnTime = reader.readSignedOnTime();
    _receivedEncryptedSignature = new byte[Signature.SIGNATURE_BYTES + 8];
    reader.readEncryptedSignature(_receivedEncryptedSignature, 0);
    _receivedIV = new byte[UDPPacket.IV_SIZE];
    reader.readIV(_receivedIV, 0);

    if (_log.shouldLog(Log.DEBUG))
      _log.debug(
          "Receive session created:Sig: "
              + Base64.encode(_receivedEncryptedSignature)
              + "receivedIV: "
              + Base64.encode(_receivedIV)
              + "AliceIP: "
              + Addresses.toString(_aliceIP)
              + " RelayTag: "
              + _receivedRelayTag
              + " SignedOn: "
              + _receivedSignedOnTime
              + ' '
              + this.toString());

    if (_currentState == OutboundState.OB_STATE_UNKNOWN
        || _currentState == OutboundState.OB_STATE_REQUEST_SENT
        || _currentState == OutboundState.OB_STATE_INTRODUCED
        || _currentState == OutboundState.OB_STATE_PENDING_INTRO)
      _currentState = OutboundState.OB_STATE_CREATED_RECEIVED;
    packetReceived();
  }
Beispiel #4
0
 /**
  *  Blocking, may take a while
  */
 public synchronized void start() {
     if (_log.shouldLog(Log.DEBUG))
         _log.debug("UPnP Start");
     _shouldBeRunning = true;
     if (!_isRunning) {
         long b = _context.clock().now();
         try {
             _isRunning = _upnp.runPlugin();
             if (_log.shouldLog(Log.INFO))
                 _log.info("UPnP runPlugin took " + (_context.clock().now() - b));
         } catch (Exception e) {
             // NPE in UPnP (ticket #728), can't let it bring us down
             if (!_errorLogged) {
                 _log.error("UPnP error, please report", e);
                 _errorLogged = true;
             }
         }
     }
     if (_isRunning) {
         _rescanner.schedule(RESCAN_LONG_DELAY);
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("UPnP Start Done");
     } else {
         _rescanner.schedule(RESCAN_SHORT_DELAY);
         // Do we have a non-loopback, non-broadcast address?
         // If not, that's why it failed (HTTPServer won't start)
         if (!Addresses.isConnected()) {
             if (!_disconLogged) {
                 _log.logAlways(Log.WARN, "UPnP start failed - no network connection?");
                 _disconLogged = true;
             }
         } else {
             _log.error("UPnP start failed - port conflict?");
         }
     }
 }
  /**
   * http://irc.codehaus.org/display/JETTY/Porting+to+jetty6
   *
   * <pre>
   * Server
   * 	HandlerCollection
   * 		ContextHandlerCollection
   * 			WebAppContext (i.e. ContextHandler)
   * 				SessionHandler
   * 				SecurityHandler
   * 				ServletHandler
   * 					servlets...
   * 			WebAppContext
   * 			...
   * 		DefaultHandler
   * 		RequestLogHandler (opt)
   * </pre>
   */
  public void startConsole() {
    File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
    boolean workDirRemoved = FileUtil.rmdir(workDir, false);
    if (!workDirRemoved)
      System.err.println("ERROR: Unable to remove Jetty temporary work directory");
    boolean workDirCreated = workDir.mkdirs();
    if (!workDirCreated)
      System.err.println("ERROR: Unable to create Jetty temporary work directory");

    // try {
    //    Log.setLog(new I2PLogger(_context));
    // } catch (Throwable t) {
    //    System.err.println("INFO: I2P Jetty logging class not found, logging to wrapper log");
    // }
    // This way it doesn't try to load Slf4jLog first
    System.setProperty("org.mortbay.log.class", "net.i2p.jetty.I2PLogger");

    // so Jetty can find WebAppConfiguration
    System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
    _server = new Server();
    _server.setGracefulShutdown(1000);

    try {
      ThreadPool ctp = new CustomThreadPoolExecutor();
      ctp.prestartAllCoreThreads();
      _server.setThreadPool(ctp);
    } catch (Throwable t) {
      // class not found...
      System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
      QueuedThreadPool qtp = new QueuedThreadPool(MAX_THREADS);
      qtp.setMinThreads(MIN_THREADS);
      qtp.setMaxIdleTimeMs(MAX_IDLE_TIME);
      _server.setThreadPool(qtp);
    }

    HandlerCollection hColl = new HandlerCollection();
    ContextHandlerCollection chColl = new ContextHandlerCollection();
    _server.addHandler(hColl);
    hColl.addHandler(chColl);
    hColl.addHandler(new DefaultHandler());

    String log = _context.getProperty("routerconsole.log");
    if (log != null) {
      File logFile = new File(log);
      if (!logFile.isAbsolute()) logFile = new File(_context.getLogDir(), "logs/" + log);
      try {
        RequestLogHandler rhl = new RequestLogHandler();
        rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
        hColl.addHandler(rhl);
      } catch (Exception ioe) {
        System.err.println("ERROR: Unable to create Jetty log: " + ioe);
      }
    }
    boolean rewrite = false;
    Properties props = webAppProperties();
    if (props.isEmpty()) {
      props.setProperty(PREFIX + ROUTERCONSOLE + ENABLED, "true");
      rewrite = true;
    }

    // Get an absolute path with a trailing slash for the webapps dir
    // We assume relative to the base install dir for backward compatibility
    File app = new File(_webAppsDir);
    if (!app.isAbsolute()) {
      app = new File(_context.getBaseDir(), _webAppsDir);
      try {
        _webAppsDir = app.getCanonicalPath();
      } catch (IOException ioe) {
      }
    }
    if (!_webAppsDir.endsWith("/")) _webAppsDir += '/';

    WebAppContext rootWebApp = null;
    ServletHandler rootServletHandler = null;
    List<Connector> connectors = new ArrayList(4);
    try {
      int boundAddresses = 0;
      Set addresses = Addresses.getAllAddresses();
      boolean hasIPV4 = addresses.contains("0.0.0.0");
      boolean hasIPV6 = addresses.contains("0:0:0:0:0:0:0:0");

      // add standard listeners
      int lport = 0;
      if (_listenPort != null) {
        try {
          lport = Integer.parseInt(_listenPort);
        } catch (NumberFormatException nfe) {
        }
        if (lport <= 0) System.err.println("Bad routerconsole port " + _listenPort);
      }
      if (lport > 0) {
        StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
        while (tok.hasMoreTokens()) {
          String host = tok.nextToken().trim();
          try {
            // Test before we add the connector, because Jetty 6 won't start if any of the
            // connectors are bad
            InetAddress test = InetAddress.getByName(host);
            if ((!hasIPV6) && (!(test instanceof Inet4Address)))
              throw new IOException("IPv6 addresses unsupported");
            if ((!hasIPV4) && (test instanceof Inet4Address))
              throw new IOException("IPv4 addresses unsupported");
            ServerSocket testSock = null;
            try {
              // On Windows, this was passing and Jetty was still failing,
              // possibly due to %scope_id ???
              // https://issues.apache.org/jira/browse/ZOOKEEPER-667
              // testSock = new ServerSocket(0, 0, test);
              // so do exactly what Jetty does in SelectChannelConnector.open()
              testSock = new ServerSocket();
              InetSocketAddress isa = new InetSocketAddress(host, 0);
              testSock.bind(isa);
            } finally {
              if (testSock != null)
                try {
                  testSock.close();
                } catch (IOException ioe) {
                }
            }
            // if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
            //    _server.addListener('[' + host + "]:" + _listenPort);
            // else
            //    _server.addListener(host + ':' + _listenPort);
            AbstractConnector lsnr;
            if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
              SelectChannelConnector slsnr = new SelectChannelConnector();
              slsnr.setUseDirectBuffers(false); // default true seems to be leaky
              lsnr = slsnr;
            } else {
              // Jetty 6 and NIO on Java 5 don't get along that well
              // Also: http://jira.codehaus.org/browse/JETTY-1238
              // "Do not use GCJ with Jetty, it will not work."
              // Actually it does if you don't use NIO
              lsnr = new SocketConnector();
            }
            lsnr.setHost(host);
            lsnr.setPort(lport);
            lsnr.setMaxIdleTime(90 * 1000); // default 10 sec
            lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
            // _server.addConnector(lsnr);
            connectors.add(lsnr);
            boundAddresses++;
          } catch (Exception ioe) {
            System.err.println(
                "Unable to bind routerconsole to " + host + " port " + _listenPort + ": " + ioe);
            System.err.println(
                "You may ignore this warning if the console is still available at http://localhost:"
                    + _listenPort);
          }
        }
        // XXX: what if listenhosts do not include 127.0.0.1? (Should that ever even happen?)
        _context.portMapper().register(PortMapper.SVC_CONSOLE, lport);
      }

      // add SSL listeners
      int sslPort = 0;
      if (_sslListenPort != null) {
        try {
          sslPort = Integer.parseInt(_sslListenPort);
        } catch (NumberFormatException nfe) {
        }
        if (sslPort <= 0) System.err.println("Bad routerconsole SSL port " + _sslListenPort);
      }
      if (sslPort > 0) {
        File keyStore = new File(_context.getConfigDir(), "keystore/console.ks");
        if (verifyKeyStore(keyStore)) {
          StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
          while (tok.hasMoreTokens()) {
            String host = tok.nextToken().trim();
            // doing it this way means we don't have to escape an IPv6 host with []
            try {
              // Test before we add the connector, because Jetty 6 won't start if any of the
              // connectors are bad
              InetAddress test = InetAddress.getByName(host);
              if ((!hasIPV6) && (!(test instanceof Inet4Address)))
                throw new IOException("IPv6 addresses unsupported");
              if ((!hasIPV4) && (test instanceof Inet4Address))
                throw new IOException("IPv4 addresses unsupported");
              ServerSocket testSock = null;
              try {
                // see comments above
                // testSock = new ServerSocket(0, 0, test);
                testSock = new ServerSocket();
                InetSocketAddress isa = new InetSocketAddress(host, 0);
                testSock.bind(isa);
              } finally {
                if (testSock != null)
                  try {
                    testSock.close();
                  } catch (IOException ioe) {
                  }
              }
              // TODO if class not found use SslChannelConnector
              // Sadly there's no common base class with the ssl methods in it
              AbstractConnector ssll;
              if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
                SslSelectChannelConnector sssll = new SslSelectChannelConnector();
                // the keystore path and password
                sssll.setKeystore(keyStore.getAbsolutePath());
                sssll.setPassword(
                    _context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
                // the X.509 cert password (if not present, verifyKeyStore() returned false)
                sssll.setKeyPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
                sssll.setUseDirectBuffers(false); // default true seems to be leaky
                ssll = sssll;
              } else {
                // Jetty 6 and NIO on Java 5 don't get along that well
                SslSocketConnector sssll = new SslSocketConnector();
                // the keystore path and password
                sssll.setKeystore(keyStore.getAbsolutePath());
                sssll.setPassword(
                    _context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
                // the X.509 cert password (if not present, verifyKeyStore() returned false)
                sssll.setKeyPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
                ssll = sssll;
              }
              ssll.setHost(host);
              ssll.setPort(sslPort);
              ssll.setMaxIdleTime(90 * 1000); // default 10 sec
              ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
              // _server.addConnector(ssll);
              connectors.add(ssll);
              boundAddresses++;
            } catch (Exception e) {
              System.err.println(
                  "Unable to bind routerconsole to "
                      + host
                      + " port "
                      + sslPort
                      + " for SSL: "
                      + e);
              if (SystemVersion.isGNU())
                System.err.println("Probably because GNU classpath does not support Sun keystores");
              System.err.println(
                  "You may ignore this warning if the console is still available at https://localhost:"
                      + sslPort);
            }
          }
          _context.portMapper().register(PortMapper.SVC_HTTPS_CONSOLE, sslPort);
        } else {
          System.err.println(
              "Unable to create or access keystore for SSL: " + keyStore.getAbsolutePath());
        }
      }

      if (boundAddresses <= 0) {
        System.err.println(
            "Unable to bind routerconsole to any address on port "
                + _listenPort
                + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
        return;
      }

      rootWebApp = new LocaleWebAppHandler(_context, "/", _webAppsDir + ROUTERCONSOLE + ".war");
      File tmpdir =
          new SecureDirectory(
              workDir, ROUTERCONSOLE + "-" + (_listenPort != null ? _listenPort : _sslListenPort));
      tmpdir.mkdir();
      rootWebApp.setTempDirectory(tmpdir);
      rootWebApp.setExtractWAR(false);
      rootWebApp.setSessionHandler(new SessionHandler());
      rootServletHandler = new ServletHandler();
      rootWebApp.setServletHandler(rootServletHandler);
      initialize(_context, rootWebApp);
      chColl.addHandler(rootWebApp);

    } catch (Exception ioe) {
      ioe.printStackTrace();
    }

    try {
      // start does a mapContexts()
      _server.start();
    } catch (Throwable me) {
      // NoClassFoundDefError from a webapp is a throwable, not an exception
      System.err.println("Error starting the Router Console server: " + me);
      me.printStackTrace();
    }

    if (_server.isRunning()) {
      // Add and start the connectors one-by-one
      boolean error = false;
      for (Connector conn : connectors) {
        try {
          _server.addConnector(conn);
          // start after adding so it gets the right thread pool
          conn.start();
        } catch (Throwable me) {
          try {
            _server.removeConnector(conn);
          } catch (Throwable t) {
            t.printStackTrace();
          }
          System.err.println("WARNING: Error starting " + conn + ": " + me);
          me.printStackTrace();
          error = true;
        }
      }
      if (error) {
        System.err.println(
            "WARNING: Error starting one or more listeners of the Router Console server.\n"
                + "If your console is still accessible at http://127.0.0.1:"
                + _listenPort
                + "/,\n"
                + "this may be a problem only with binding to the IPV6 address ::1.\n"
                + "If so, you may ignore this error, or remove the\n"
                + "\"::1,\" in the \"clientApp.0.args\" line of the clients.config file.");
      }
    }

    // Start all the other webapps after the server is up,
    // so things start faster.
    // Jetty 6 starts the connector before the router console is ready
    // This also prevents one webapp from breaking the whole thing
    List<String> notStarted = new ArrayList();
    if (_server.isRunning()) {
      File dir = new File(_webAppsDir);
      String fileNames[] = dir.list(WarFilenameFilter.instance());
      if (fileNames != null) {
        for (int i = 0; i < fileNames.length; i++) {
          String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
          String enabled = props.getProperty(PREFIX + appName + ENABLED);
          if (!"false".equals(enabled)) {
            try {
              String path = new File(dir, fileNames[i]).getCanonicalPath();
              WebAppStarter.startWebApp(_context, chColl, appName, path);
              if (enabled == null) {
                // do this so configclients.jsp knows about all apps from reading the config
                props.setProperty(PREFIX + appName + ENABLED, "true");
                rewrite = true;
              }
            } catch (Throwable t) {
              System.err.println("ERROR: Failed to start " + appName + ' ' + t);
              t.printStackTrace();
              notStarted.add(appName);
            }
          } else {
            notStarted.add(appName);
          }
        }
        changeState(RUNNING);
      }
    } else {
      System.err.println("ERROR: Router console did not start, not starting webapps");
      changeState(START_FAILED);
    }

    if (rewrite) storeWebAppProperties(_context, props);

    if (rootServletHandler != null && notStarted.size() > 0) {
      // map each not-started webapp to the error page
      ServletHolder noWebApp = rootServletHandler.getServlet("net.i2p.router.web.jsp.nowebapp_jsp");
      for (int i = 0; i < notStarted.size(); i++) {
        // we want a new handler for each one since if the webapp is started we remove the
        // handler???
        try {
          if (noWebApp != null) {
            String path = '/' + notStarted.get(i);
            // LocaleWebAppsHandler adds a .jsp
            rootServletHandler.addServletWithMapping(noWebApp, path + ".jsp");
            rootServletHandler.addServletWithMapping(noWebApp, path + "/*");
          } else {
            System.err.println("Can't find nowebapp.jsp?");
          }
        } catch (Throwable me) {
          System.err.println(me);
          me.printStackTrace();
        }
      }
    }

    Thread t = new I2PAppThread(new StatSummarizer(), "StatSummarizer", true);
    t.setPriority(Thread.NORM_PRIORITY - 1);
    t.start();

    ConsoleUpdateManager um = new ConsoleUpdateManager(_context);
    um.start();

    if (PluginStarter.pluginsEnabled(_context)) {
      t = new I2PAppThread(new PluginStarter(_context), "PluginStarter", true);
      t.setPriority(Thread.NORM_PRIORITY - 1);
      t.start();
      _context.addShutdownTask(new PluginStopper(_context));
    }
    // stat summarizer registers its own hook
    _context.addShutdownTask(new ServerShutdown());
    ConfigServiceHandler.registerSignalHandler(_context);
  }