Search in sources :

Example 16 with RouterInfo

use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.

the class BuildRequestor method createTunnelBuildMessage.

/**
 * @since 0.7.12
 */
/**
 **
 *we can assume everybody supports variable now...
 *keep this here for the next time we change the build protocol
 *    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;
 *    }
 ***
 */
/**
 *  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;
    boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS;
    if (cfg.isInbound()) {
        // replyTunnel = 0; // as above
        replyRouter = ctx.routerHash();
    /**
     **
     *we can assume everybody supports variable now...
     *keep this here for the next time we change the build protocol
     *            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);
    /**
     **
     *we can assume everybody supports variable now
     *keep this here for the next time we change the build protocol
     *            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);
    // randomized placement within the message
    Collections.shuffle(order, ctx.random());
    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;
}
Also used : Log(net.i2p.util.Log) PublicKey(net.i2p.data.PublicKey) RouterInfo(net.i2p.data.router.RouterInfo) VariableTunnelBuildMessage(net.i2p.data.i2np.VariableTunnelBuildMessage) TunnelBuildMessage(net.i2p.data.i2np.TunnelBuildMessage) VariableTunnelBuildMessage(net.i2p.data.i2np.VariableTunnelBuildMessage) Hash(net.i2p.data.Hash)

Example 17 with RouterInfo

use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.

the class BuildRequestor method request.

/**
 *  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;
    }
    // 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);
    }
    // + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch));
    return true;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) Log(net.i2p.util.Log) RouterInfo(net.i2p.data.router.RouterInfo) VariableTunnelBuildMessage(net.i2p.data.i2np.VariableTunnelBuildMessage) TunnelBuildMessage(net.i2p.data.i2np.TunnelBuildMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash) TunnelManagerFacade(net.i2p.router.TunnelManagerFacade)

Example 18 with RouterInfo

use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.

the class ConnectChecker method canConnect.

/**
 *  Can "from" connect to "to" based on published addresses?
 *
 *  This is intended for tunnel candidates, where we already have
 *  the RI. Will not force RI lookups.
 *  Either from or to may be us.
 *
 *  This is best effort, as we can't know for sure.
 *  Published addresses or introducers may have changed.
 *  Even if a can't connect to b, they may already be connected
 *  as b connected to a.
 *
 *  @return true if we don't have either RI
 *  @since 0.9.34
 */
public boolean canConnect(Hash from, Hash to) {
    Hash us = ctx.routerHash();
    if (us == null)
        return true;
    boolean usf = from.equals(us);
    if (usf && ctx.commSystem().isEstablished(to))
        return true;
    boolean ust = to.equals(us);
    if (ust && ctx.commSystem().isEstablished(from))
        return true;
    RouterInfo rt = ctx.netDb().lookupRouterInfoLocally(to);
    if (rt == null)
        return true;
    RouterInfo rf = ctx.netDb().lookupRouterInfoLocally(from);
    if (rf == null)
        return true;
    int ct;
    if (ust) {
        // to us
        ct = getInboundMask(rt);
    } else {
        Collection<RouterAddress> at = rt.getAddresses();
        // assume nothing if hidden
        if (at.isEmpty())
            return false;
        ct = getConnectMask(at);
    }
    int cf;
    if (usf) {
        // from us
        cf = getOutboundMask(rf);
    } else {
        Collection<RouterAddress> a = rf.getAddresses();
        if (a.isEmpty()) {
            // assume IPv4 if hidden
            cf = NTCP_V4 | SSU_V4;
        } else {
            cf = getConnectMask(a);
        }
    }
    boolean rv = (ct & cf) != 0;
    if (!rv && log.shouldWarn()) {
        log.warn("Cannot connect: " + (usf ? "us" : from.toString()) + " with mask " + cf + "\nto " + (ust ? "us" : to.toString()) + " with mask " + ct);
    }
    return rv;
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) RouterAddress(net.i2p.data.router.RouterAddress) Hash(net.i2p.data.Hash)

Example 19 with RouterInfo

use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.

the class FloodfillVerifyStoreJob method runJob.

/**
 *  Query a random floodfill for the leaseset or routerinfo
 *  that we just stored to a (hopefully different) floodfill peer.
 *
 *  If it fails (after a timeout period), resend the data.
 *  If the queried data is older than what we stored, that counts as a fail.
 */
public void runJob() {
    _target = pickTarget();
    if (_target == null) {
        _facade.verifyFinished(_key);
        return;
    }
    boolean isInboundExploratory;
    TunnelInfo replyTunnelInfo;
    if (_isRouterInfo || getContext().keyRing().get(_key) != null) {
        replyTunnelInfo = getContext().tunnelManager().selectInboundExploratoryTunnel(_target);
        isInboundExploratory = true;
    } else {
        replyTunnelInfo = getContext().tunnelManager().selectInboundTunnel(_key, _target);
        isInboundExploratory = false;
    }
    if (replyTunnelInfo == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("No inbound tunnels to get a reply from!");
        return;
    }
    DatabaseLookupMessage lookup = buildLookup(replyTunnelInfo);
    // If we are verifying a leaseset, use the destination's own tunnels,
    // to avoid association by the exploratory tunnel OBEP.
    // Unless it is an encrypted leaseset.
    TunnelInfo outTunnel;
    if (_isRouterInfo || getContext().keyRing().get(_key) != null)
        outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(_target);
    else
        outTunnel = getContext().tunnelManager().selectOutboundTunnel(_key, _target);
    if (outTunnel == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("No outbound tunnels to verify a store");
        _facade.verifyFinished(_key);
        return;
    }
    // garlic encrypt to hide contents from the OBEP
    RouterInfo peer = _facade.lookupRouterInfoLocally(_target);
    if (peer == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Fail finding target RI");
        _facade.verifyFinished(_key);
        return;
    }
    if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
        // register the session with the right SKM
        MessageWrapper.OneTimeSession sess;
        if (isInboundExploratory) {
            sess = MessageWrapper.generateSession(getContext());
        } else {
            sess = MessageWrapper.generateSession(getContext(), _key);
            if (sess == null) {
                if (_log.shouldLog(Log.WARN))
                    _log.warn("No SKM to reply to");
                _facade.verifyFinished(_key);
                return;
            }
        }
        if (_log.shouldLog(Log.INFO))
            _log.info("Requesting encrypted reply from " + _target + ' ' + sess.key + ' ' + sess.tag);
        lookup.setReplySession(sess.key, sess.tag);
    }
    Hash fromKey;
    if (_isRouterInfo)
        fromKey = null;
    else
        fromKey = _key;
    _wrappedMessage = MessageWrapper.wrap(getContext(), lookup, fromKey, peer);
    if (_wrappedMessage == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Fail Garlic encrypting");
        _facade.verifyFinished(_key);
        return;
    }
    I2NPMessage sent = _wrappedMessage.getMessage();
    if (_log.shouldLog(Log.INFO))
        _log.info("Starting verify (stored " + _key + " to " + _sentTo + "), asking " + _target);
    _sendTime = getContext().clock().now();
    _expiration = _sendTime + VERIFY_TIMEOUT;
    getContext().messageRegistry().registerPending(new VerifyReplySelector(), new VerifyReplyJob(getContext()), new VerifyTimeoutJob(getContext()));
    getContext().tunnelDispatcher().dispatchOutbound(sent, outTunnel.getSendTunnelId(0), _target);
}
Also used : DatabaseLookupMessage(net.i2p.data.i2np.DatabaseLookupMessage) RouterInfo(net.i2p.data.router.RouterInfo) I2NPMessage(net.i2p.data.i2np.I2NPMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash)

Example 20 with RouterInfo

use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.

the class HandleFloodfillDatabaseStoreMessageJob method sendAck.

private void sendAck(Hash storedKey) {
    DeliveryStatusMessage msg = new DeliveryStatusMessage(getContext());
    msg.setMessageId(_message.getReplyToken());
    // Randomize for a little protection against clock-skew fingerprinting.
    // But the "arrival" isn't used for anything, right?
    // TODO just set to 0?
    // TODO we have no session to garlic wrap this with, needs new message
    msg.setArrival(getContext().clock().now() - getContext().random().nextInt(3 * 1000));
    // may be null
    TunnelId replyTunnel = _message.getReplyTunnel();
    // A store of our own RI, only if we are not FF
    DatabaseStoreMessage msg2;
    if ((getContext().netDb().floodfillEnabled() && !getContext().router().gracefulShutdownInProgress()) || storedKey.equals(getContext().routerHash())) {
        // don't send our RI if the store was our RI (from PeerTestJob)
        msg2 = null;
    } else {
        // we aren't ff, send a go-away message
        msg2 = new DatabaseStoreMessage(getContext());
        RouterInfo me = getContext().router().getRouterInfo();
        msg2.setEntry(me);
        if (_log.shouldWarn())
            _log.warn("Got a store w/ reply token, but we aren't ff: from: " + _from + " fromHash: " + _fromHash + " msg: " + _message, new Exception());
    }
    Hash toPeer = _message.getReplyGateway();
    boolean toUs = getContext().routerHash().equals(toPeer);
    // else through an exploratory tunnel.
    if (toUs && replyTunnel != null) {
        // if we are the gateway, act as if we received it
        TunnelGatewayMessage tgm = new TunnelGatewayMessage(getContext());
        tgm.setMessage(msg);
        tgm.setTunnelId(replyTunnel);
        tgm.setMessageExpiration(msg.getMessageExpiration());
        getContext().tunnelDispatcher().dispatch(tgm);
        if (msg2 != null) {
            TunnelGatewayMessage tgm2 = new TunnelGatewayMessage(getContext());
            tgm2.setMessage(msg2);
            tgm2.setTunnelId(replyTunnel);
            tgm2.setMessageExpiration(msg.getMessageExpiration());
            getContext().tunnelDispatcher().dispatch(tgm2);
        }
    } else if (toUs || getContext().commSystem().isEstablished(toPeer)) {
        Job send = new SendMessageDirectJob(getContext(), msg, toPeer, REPLY_TIMEOUT, MESSAGE_PRIORITY);
        send.runJob();
        if (msg2 != null) {
            Job send2 = new SendMessageDirectJob(getContext(), msg2, toPeer, REPLY_TIMEOUT, MESSAGE_PRIORITY);
            send2.runJob();
        }
    } else {
        // pick tunnel with endpoint closest to toPeer
        TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(toPeer);
        if (outTunnel == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("No outbound tunnel could be found");
            return;
        }
        getContext().tunnelDispatcher().dispatchOutbound(msg, outTunnel.getSendTunnelId(0), replyTunnel, toPeer);
        if (msg2 != null)
            getContext().tunnelDispatcher().dispatchOutbound(msg2, outTunnel.getSendTunnelId(0), replyTunnel, toPeer);
    }
}
Also used : TunnelGatewayMessage(net.i2p.data.i2np.TunnelGatewayMessage) RouterInfo(net.i2p.data.router.RouterInfo) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash) SendMessageDirectJob(net.i2p.router.message.SendMessageDirectJob) Job(net.i2p.router.Job) TunnelId(net.i2p.data.TunnelId) SendMessageDirectJob(net.i2p.router.message.SendMessageDirectJob) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage)

Aggregations

RouterInfo (net.i2p.data.router.RouterInfo)95 Hash (net.i2p.data.Hash)45 ArrayList (java.util.ArrayList)18 RouterAddress (net.i2p.data.router.RouterAddress)17 DataFormatException (net.i2p.data.DataFormatException)11 IOException (java.io.IOException)10 RouterIdentity (net.i2p.data.router.RouterIdentity)10 DatabaseEntry (net.i2p.data.DatabaseEntry)9 OutNetMessage (net.i2p.router.OutNetMessage)9 File (java.io.File)8 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)8 Properties (java.util.Properties)7 LeaseSet (net.i2p.data.LeaseSet)6 BigInteger (java.math.BigInteger)5 Date (java.util.Date)5 SigType (net.i2p.crypto.SigType)5 TunnelId (net.i2p.data.TunnelId)5 TunnelInfo (net.i2p.router.TunnelInfo)5 FileOutputStream (java.io.FileOutputStream)4 HashMap (java.util.HashMap)4