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; } }
public TunnelGatewayZeroHop(RouterContext context, TunnelCreatorConfig config) { super(context, null, null, null); _config = config; if (config.isInbound()) _inDistributor = new InboundMessageDistributor(context, config.getDestination()); else _outDistributor = new OutboundMessageDistributor(context, 400); }
private TunnelCreatorConfig configOutbound(I2PAppContext ctx) { _peers = new Hash[4]; _pubKeys = new PublicKey[_peers.length]; _privKeys = new PrivateKey[_peers.length]; for (int i = 0; i < _peers.length; i++) { byte buf[] = new byte[Hash.HASH_LENGTH]; Arrays.fill(buf, (byte) i); // consistent for repeatability Hash h = new Hash(buf); _peers[i] = h; Object kp[] = ctx.keyGenerator().generatePKIKeypair(); _pubKeys[i] = (PublicKey) kp[0]; _privKeys[i] = (PrivateKey) kp[1]; } TunnelCreatorConfig cfg = new TunnelCreatorConfig(null, _peers.length, false); long now = ctx.clock().now(); // peers[] is ordered endpoint first, but cfg.getPeer() is ordered gateway first for (int i = 0; i < _peers.length; i++) { cfg.setPeer(i, _peers[i]); HopConfig hop = cfg.getConfig(i); hop.setExpiration(now + 10 * 60 * 1000); hop.setIVKey(ctx.keyGenerator().generateSessionKey()); hop.setLayerKey(ctx.keyGenerator().generateSessionKey()); hop.setReplyKey(ctx.keyGenerator().generateSessionKey()); byte iv[] = new byte[BuildRequestRecord.IV_SIZE]; Arrays.fill(iv, (byte) i); // consistent for repeatability hop.setReplyIV(new ByteArray(iv)); hop.setReceiveTunnelId(new TunnelId(i + 1)); } return cfg; }
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 }
/** * Add a message to be sent down the tunnel (immediately forwarding it to the {@link * InboundMessageDistributor} or {@link OutboundMessageDistributor}, as necessary). * * @param msg message to be sent through the tunnel * @param toRouter router to send to after the endpoint (or null for endpoint processing) * @param toTunnel tunnel to send to after the endpoint (or null for endpoint or router * processing) */ @Override public void add(I2NPMessage msg, Hash toRouter, TunnelId toTunnel) { if (_log.shouldLog(Log.DEBUG)) _log.debug( "zero hop gateway: distribute " + (_config.isInbound() ? "inbound" : " outbound") + " to " + (toRouter != null ? toRouter.toBase64().substring(0, 4) : "") + "." + (toTunnel != null ? toTunnel.getTunnelId() + "" : "") + ": " + msg); if (_config.isInbound()) { _inDistributor.distribute(msg, toRouter, toTunnel); } else { _outDistributor.distribute(msg, toRouter, toTunnel); } _config.incrementProcessedMessages(); }
private void send(TunnelDataMessage msg, RouterInfo ri) { if (_log.shouldLog(Log.DEBUG)) _log.debug("forwarding encrypted data out " + _config + ": " + msg.getUniqueId()); OutNetMessage m = new OutNetMessage(_context); m.setMessage(msg); m.setExpiration(msg.getMessageExpiration()); m.setTarget(ri); m.setPriority(PRIORITY); _context.outNetMessagePool().add(m); _config.incrementProcessedMessages(); }
/** * Add a message to be sent down the tunnel, where we are the inbound gateway. This requires * converting the message included in the TGM from an UnknownI2NPMessage to the correct message * class. See TunnelGatewayMessage for details. * * @param msg message received to be sent through the tunnel */ @Override public void add(TunnelGatewayMessage msg) { I2NPMessage imsg = msg.getMessage(); if (_config.isInbound()) { if (imsg instanceof UnknownI2NPMessage) { // Do the delayed deserializing - convert to a standard message class try { UnknownI2NPMessage umsg = (UnknownI2NPMessage) imsg; imsg = umsg.convert(); } catch (I2NPMessageException ime) { if (_log.shouldLog(Log.WARN)) _log.warn("Unable to convert to std. msg. class at zero-hop IBGW", ime); return; } } } add(imsg, null, null); }
@Override public String toString() { StringBuilder buf = new StringBuilder(64); if (_receiveTunnelId != null) { buf.append("recv on "); buf.append(DataHelper.fromLong(_receiveTunnelId, 0, 4)); buf.append(" "); } if (_sendTo != null) { buf.append("send to ").append(_sendTo.toBase64().substring(0, 4)).append(":"); if (_sendTunnelId != null) buf.append(DataHelper.fromLong(_sendTunnelId, 0, 4)); } buf.append(" expiring on ").append(TunnelCreatorConfig.format(_expiration)); buf.append(" having transferred ").append(_messagesProcessed).append("KB"); return buf.toString(); }
/** * The next hop * * @return non-null * @since 0.9.3 */ public Hash getSendTo() { return _config.getPeer(1); }
private void runTest() { I2PAppContext ctx = I2PAppContext.getGlobalContext(); Log log = ctx.logManager().getLog(getClass()); List order = pickOrder(ctx); TunnelCreatorConfig cfg = createConfig(ctx); _replyRouter = new Hash(); byte h[] = new byte[Hash.HASH_LENGTH]; Arrays.fill(h, (byte) 0xFF); _replyRouter.setData(h); _replyTunnel = 42; // populate and encrypt the message BuildMessageGenerator gen = new BuildMessageGenerator(); TunnelBuildMessage msg = new TunnelBuildMessage(ctx); for (int i = 0; i < BuildMessageGenerator.ORDER.length; i++) { int hop = ((Integer) order.get(i)).intValue(); PublicKey key = null; if (hop < _pubKeys.length) key = _pubKeys[hop]; gen.createRecord(i, hop, msg, cfg, _replyRouter, _replyTunnel, ctx, key); } gen.layeredEncrypt(ctx, msg, cfg, order); log.debug( "\n================================================================" + "\nMessage fully encrypted" + "\n================================================================"); // now msg is fully encrypted, so lets go through the hops, decrypting and replying // as necessary BuildMessageProcessor proc = new BuildMessageProcessor(ctx); for (int i = 0; i < cfg.getLength(); i++) { // this not only decrypts the current hop's record, but encrypts the other records // with the reply key BuildRequestRecord req = proc.decrypt(ctx, msg, _peers[i], _privKeys[i]); if (req == null) { // no records matched the _peers[i], or the decryption failed throw new RuntimeException("foo @ " + i); } long ourId = req.readReceiveTunnelId(); byte replyIV[] = req.readReplyIV(); long nextId = req.readNextTunnelId(); Hash nextPeer = req.readNextIdentity(); boolean isInGW = req.readIsInboundGateway(); boolean isOutEnd = req.readIsOutboundEndpoint(); long time = req.readRequestTime(); long now = (ctx.clock().now() / (60l * 60l * 1000l)) * (60 * 60 * 1000); int ourSlot = -1; BuildResponseRecord resp = new BuildResponseRecord(); byte reply[] = resp.create(ctx, 0, req.readReplyKey(), req.readReplyIV(), -1); for (int j = 0; j < TunnelBuildMessage.RECORD_COUNT; j++) { if (msg.getRecord(j) == null) { ourSlot = j; msg.setRecord(j, new ByteArray(reply)); break; } } log.debug( "Read slot " + ourSlot + " containing hop " + i + " @ " + _peers[i].toBase64() + " receives on " + ourId + " w/ replyIV " + Base64.encode(replyIV) + " sending to " + nextId + " on " + nextPeer.toBase64() + " inGW? " + isInGW + " outEnd? " + isOutEnd + " time difference " + (now - time)); } log.debug( "\n================================================================" + "\nAll hops traversed and replies gathered" + "\n================================================================"); // now all of the replies are populated, toss 'em into a reply message and handle it TunnelBuildReplyMessage reply = new TunnelBuildReplyMessage(ctx); for (int i = 0; i < TunnelBuildMessage.RECORD_COUNT; i++) reply.setRecord(i, msg.getRecord(i)); BuildReplyHandler handler = new BuildReplyHandler(); int statuses[] = handler.decrypt(ctx, reply, cfg, order); if (statuses == null) throw new RuntimeException("bar"); boolean allAgree = true; for (int i = 0; i < cfg.getLength(); i++) { Hash peer = cfg.getPeer(i); int record = ((Integer) order.get(i)).intValue(); if (statuses[record] != 0) allAgree = false; // else // penalize peer according to the rejection cause } log.debug( "\n================================================================" + "\nAll peers agree? " + allAgree + "\n================================================================"); }