Exemple #1
0
  public long receiveEncrypted(byte encrypted[]) {
    TunnelDataMessage msg = new TunnelDataMessage(_context);
    msg.setData(encrypted);
    msg.setTunnelId(_config.getConfig(0).getSendTunnel());

    if (_log.shouldLog(Log.DEBUG))
      _log.debug("received encrypted, sending out " + _config + ": " + msg);
    RouterInfo ri = _nextHopCache;
    if (ri == null) ri = _context.netDb().lookupRouterInfoLocally(_config.getPeer(1));
    if (ri != null) {
      _nextHopCache = ri;
      send(msg, ri);
      return msg.getUniqueId();
    } else {
      // It should be rare to forget the router info for a peer in our own tunnel.
      if (_log.shouldLog(Log.WARN))
        _log.warn("lookup of " + _config.getPeer(1) + " required for " + msg);
      _context
          .netDb()
          .lookupRouterInfo(
              _config.getPeer(1),
              new SendJob(_context, msg),
              new FailedJob(_context),
              MAX_LOOKUP_TIME);
      return -1;
    }
  }
Exemple #2
0
 public OutboundReceiver(RouterContext ctx, TunnelCreatorConfig cfg) {
   _context = ctx;
   _log = ctx.logManager().getLog(OutboundReceiver.class);
   _config = cfg;
   _nextHopCache = _context.netDb().lookupRouterInfoLocally(_config.getPeer(1));
   // all createRateStat() in TunnelDispatcher
 }
 /** Die a horrible death. Cannot be restarted. */
 public synchronized void stopRunning() {
   if (_dead) return;
   if (_context.router().isAlive() && _log.shouldLog(Log.WARN))
     _log.warn(
         "Stop the I2CP connection!  current leaseSet: " + _currentLeaseSet,
         new Exception("Stop client connection"));
   _dead = true;
   // we need these keys to unpublish the leaseSet
   if (_reader != null) _reader.stopReading();
   if (_writer != null) _writer.stopWriting();
   if (_socket != null)
     try {
       _socket.close();
     } catch (IOException ioe) {
     }
   _messages.clear();
   _acceptedPending.clear();
   if (_sessionKeyManager != null) _sessionKeyManager.shutdown();
   _manager.unregisterConnection(this);
   if (_currentLeaseSet != null) _context.netDb().unpublish(_currentLeaseSet);
   _leaseRequest = null;
   synchronized (_alreadyProcessed) {
     _alreadyProcessed.clear();
   }
   // _config = null;
   // _manager = null;
 }
Exemple #4
0
  /**
   * If the tunnel is short enough, and everybody in the tunnel, and the OBEP or IBGW for the paired
   * tunnel, all support the new variable-sized tunnel build message, then use that, otherwise the
   * old 8-entry version.
   *
   * @return null on error
   */
  private static TunnelBuildMessage createTunnelBuildMessage(
      RouterContext ctx,
      TunnelPool pool,
      PooledTunnelCreatorConfig cfg,
      TunnelInfo pairedTunnel,
      BuildExecutor exec) {
    Log log = ctx.logManager().getLog(BuildRequestor.class);
    long replyTunnel = 0;
    Hash replyRouter = null;
    boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS;
    if (cfg.isInbound()) {
      // replyTunnel = 0; // as above
      replyRouter = ctx.routerHash();
      if (useVariable) {
        // check the reply OBEP and all the tunnel peers except ourselves
        if (!supportsVariable(ctx, pairedTunnel.getPeer(pairedTunnel.getLength() - 1))) {
          useVariable = false;
        } else {
          for (int i = 0; i < cfg.getLength() - 1; i++) {
            if (!supportsVariable(ctx, cfg.getPeer(i))) {
              useVariable = false;
              break;
            }
          }
        }
      }
    } else {
      replyTunnel = pairedTunnel.getReceiveTunnelId(0).getTunnelId();
      replyRouter = pairedTunnel.getPeer(0);
      if (useVariable) {
        // check the reply IBGW and all the tunnel peers except ourselves
        if (!supportsVariable(ctx, replyRouter)) {
          useVariable = false;
        } else {
          for (int i = 1; i < cfg.getLength() - 1; i++) {
            if (!supportsVariable(ctx, cfg.getPeer(i))) {
              useVariable = false;
              break;
            }
          }
        }
      }
    }

    // populate and encrypt the message
    TunnelBuildMessage msg;
    List<Integer> order;
    if (useVariable) {
      if (cfg.getLength() <= SHORT_RECORDS) {
        msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS);
        order = new ArrayList<Integer>(SHORT_ORDER);
      } else {
        msg = new VariableTunnelBuildMessage(ctx, MEDIUM_RECORDS);
        order = new ArrayList<Integer>(MEDIUM_ORDER);
      }
    } else {
      msg = new TunnelBuildMessage(ctx);
      order = new ArrayList<Integer>(ORDER);
    }

    // This is in BuildExecutor.buildTunnel() now
    // long replyMessageId = ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE);
    // cfg.setReplyMessageId(replyMessageId);

    Collections.shuffle(order, ctx.random()); // randomized placement within the message
    cfg.setReplyOrder(order);

    if (log.shouldLog(Log.DEBUG)) log.debug("Build order: " + order + " for " + cfg);

    for (int i = 0; i < msg.getRecordCount(); i++) {
      int hop = order.get(i).intValue();
      PublicKey key = null;

      if (BuildMessageGenerator.isBlank(cfg, hop)) {
        // erm, blank
      } else {
        Hash peer = cfg.getPeer(hop);
        RouterInfo peerInfo = ctx.netDb().lookupRouterInfoLocally(peer);
        if (peerInfo == null) {
          if (log.shouldLog(Log.WARN))
            log.warn(
                "Peer selected for hop "
                    + i
                    + "/"
                    + hop
                    + " was not found locally: "
                    + peer
                    + " for "
                    + cfg);
          return null;
        } else {
          key = peerInfo.getIdentity().getPublicKey();
        }
      }
      if (log.shouldLog(Log.DEBUG))
        log.debug(cfg.getReplyMessageId() + ": record " + i + "/" + hop + " has key " + key);
      BuildMessageGenerator.createRecord(i, hop, msg, cfg, replyRouter, replyTunnel, ctx, key);
    }
    BuildMessageGenerator.layeredEncrypt(ctx, msg, cfg, order);

    return msg;
  }
Exemple #5
0
 /** @since 0.7.12 */
 private static boolean supportsVariable(RouterContext ctx, Hash h) {
   RouterInfo ri = ctx.netDb().lookupRouterInfoLocally(h);
   if (ri == null) return false;
   String v = ri.getVersion();
   return VersionComparator.comp(v, MIN_VARIABLE_VERSION) >= 0;
 }
Exemple #6
0
  /**
   * Send out a build request message.
   *
   * @param cfg ReplyMessageId must be set
   * @return success
   */
  public static boolean request(
      RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, BuildExecutor exec) {
    // new style crypto fills in all the blanks, while the old style waits for replies to fill in
    // the next hop, etc
    prepare(ctx, cfg);

    if (cfg.getLength() <= 1) {
      buildZeroHop(ctx, pool, cfg, exec);
      return true;
    }

    Log log = ctx.logManager().getLog(BuildRequestor.class);
    cfg.setTunnelPool(pool);

    TunnelInfo pairedTunnel = null;
    Hash farEnd = cfg.getFarEnd();
    TunnelManagerFacade mgr = ctx.tunnelManager();
    boolean isInbound = pool.getSettings().isInbound();
    if (pool.getSettings().isExploratory() || !usePairedTunnels(ctx)) {
      if (isInbound) pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd);
      else pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd);
    } else {
      // building a client tunnel
      if (isInbound)
        pairedTunnel = mgr.selectOutboundTunnel(pool.getSettings().getDestination(), farEnd);
      else pairedTunnel = mgr.selectInboundTunnel(pool.getSettings().getDestination(), farEnd);
      if (pairedTunnel == null) {
        if (isInbound) {
          // random more reliable than closest ??
          // pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd);
          pairedTunnel = mgr.selectOutboundTunnel();
          if (pairedTunnel != null
              && pairedTunnel.getLength() <= 1
              && mgr.getOutboundSettings().getLength() > 0
              && mgr.getOutboundSettings().getLength()
                      + mgr.getOutboundSettings().getLengthVariance()
                  > 0) {
            // don't build using a zero-hop expl.,
            // as it is both very bad for anonomyity,
            // and it takes a build slot away from exploratory
            pairedTunnel = null;
          }
        } else {
          // random more reliable than closest ??
          // pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd);
          pairedTunnel = mgr.selectInboundTunnel();
          if (pairedTunnel != null
              && pairedTunnel.getLength() <= 1
              && mgr.getInboundSettings().getLength() > 0
              && mgr.getInboundSettings().getLength() + mgr.getInboundSettings().getLengthVariance()
                  > 0) {
            // ditto
            pairedTunnel = null;
          }
        }
        if (pairedTunnel != null && log.shouldLog(Log.INFO))
          log.info("Couldn't find a paired tunnel for " + cfg + ", using exploratory tunnel");
      }
    }
    if (pairedTunnel == null) {
      if (log.shouldLog(Log.WARN))
        log.warn("Tunnel build failed, as we couldn't find a paired tunnel for " + cfg);
      exec.buildComplete(cfg, pool);
      // Not even an exploratory tunnel? We are in big trouble.
      // Let's not spin through here too fast.
      // But don't let a client tunnel waiting for exploratories slow things down too much,
      // as there may be other tunnel pools who can build
      int ms = pool.getSettings().isExploratory() ? 250 : 25;
      try {
        Thread.sleep(ms);
      } catch (InterruptedException ie) {
      }
      return false;
    }

    // long beforeCreate = System.currentTimeMillis();
    TunnelBuildMessage msg = createTunnelBuildMessage(ctx, pool, cfg, pairedTunnel, exec);
    // long createTime = System.currentTimeMillis()-beforeCreate;
    if (msg == null) {
      if (log.shouldLog(Log.WARN))
        log.warn("Tunnel build failed, as we couldn't create the tunnel build message for " + cfg);
      exec.buildComplete(cfg, pool);
      return false;
    }

    // cfg.setPairedTunnel(pairedTunnel);

    // long beforeDispatch = System.currentTimeMillis();
    if (cfg.isInbound()) {
      if (log.shouldLog(Log.INFO))
        log.info(
            "Sending the tunnel build request "
                + msg.getUniqueId()
                + " out the tunnel "
                + pairedTunnel
                + " to "
                + cfg.getPeer(0)
                + " for "
                + cfg
                + " waiting for the reply of "
                + cfg.getReplyMessageId());
      // send it out a tunnel targetting the first hop
      // TODO - would be nice to have a TunnelBuildFirstHopFailJob queued if the
      // pairedTunnel is zero-hop, but no way to do that?
      ctx.tunnelDispatcher().dispatchOutbound(msg, pairedTunnel.getSendTunnelId(0), cfg.getPeer(0));
    } else {
      if (log.shouldLog(Log.INFO))
        log.info(
            "Sending the tunnel build request directly to "
                + cfg.getPeer(1)
                + " for "
                + cfg
                + " waiting for the reply of "
                + cfg.getReplyMessageId()
                + " with msgId="
                + msg.getUniqueId());
      // send it directly to the first hop
      // Add some fuzz to the TBM expiration to make it harder to guess how many hops
      // or placement in the tunnel
      msg.setMessageExpiration(
          ctx.clock().now() + BUILD_MSG_TIMEOUT + ctx.random().nextLong(20 * 1000));
      // We set the OutNetMessage expiration much shorter, so that the
      // TunnelBuildFirstHopFailJob fires before the 13s build expiration.
      RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(cfg.getPeer(1));
      if (peer == null) {
        if (log.shouldLog(Log.WARN))
          log.warn("Could not find the next hop to send the outbound request to: " + cfg);
        exec.buildComplete(cfg, pool);
        return false;
      }
      OutNetMessage outMsg =
          new OutNetMessage(ctx, msg, ctx.clock().now() + FIRST_HOP_TIMEOUT, PRIORITY, peer);
      outMsg.setOnFailedSendJob(new TunnelBuildFirstHopFailJob(ctx, pool, cfg, exec));
      ctx.outNetMessagePool().add(outMsg);
    }
    // if (log.shouldLog(Log.DEBUG))
    //    log.debug("Tunnel build message " + msg.getUniqueId() + " created in " + createTime
    //              + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch));
    return true;
  }