use of net.i2p.data.TunnelId in project i2p.i2p by i2p.
the class InboundMessageDistributor method distribute.
public void distribute(I2NPMessage msg, Hash target, TunnelId tunnel) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("IBMD for " + _client + " to " + target + " / " + tunnel + " : " + msg);
// allow messages on client tunnels even after client disconnection, as it may
// include e.g. test messages, etc. DataMessages will be dropped anyway
/*
if ( (_client != null) && (!_context.clientManager().isLocal(_client)) ) {
if (_log.shouldLog(Log.INFO))
_log.info("Not distributing a message, as it came down a client's tunnel ("
+ _client.toBase64() + ") after the client disconnected: " + msg);
return;
}
*/
int type = msg.getType();
// if the message came down a client tunnel:
if (_client != null) {
switch(type) {
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
/**
**
* DatabaseSearchReplyMessage orig = (DatabaseSearchReplyMessage) msg;
* if (orig.getNumReplies() > 0) {
* if (_log.shouldLog(Log.INFO))
* _log.info("Removing replies from a DSRM down a tunnel for " + _client + ": " + msg);
* DatabaseSearchReplyMessage newMsg = new DatabaseSearchReplyMessage(_context);
* newMsg.setFromHash(orig.getFromHash());
* newMsg.setSearchKey(orig.getSearchKey());
* msg = newMsg;
* }
***
*/
break;
case DatabaseStoreMessage.MESSAGE_TYPE:
DatabaseStoreMessage dsm = (DatabaseStoreMessage) msg;
if (dsm.getEntry().getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
// Todo: if peer was ff and RI is not ff, queue for exploration in netdb (but that isn't part of the facade now)
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping DSM down a tunnel for " + _client + ": " + msg);
// Handle safely by just updating the caps table, after doing basic validation
Hash key = dsm.getKey();
if (_context.routerHash().equals(key))
return;
RouterInfo ri = (RouterInfo) dsm.getEntry();
if (!key.equals(ri.getIdentity().getHash()))
return;
if (!ri.isValid())
return;
RouterInfo oldri = _context.netDb().lookupRouterInfoLocally(key);
// only update if RI is newer and non-ff
if (oldri != null && oldri.getPublished() < ri.getPublished() && !FloodfillNetworkDatabaseFacade.isFloodfill(ri)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Updating caps for RI " + key + " from \"" + oldri.getCapabilities() + "\" to \"" + ri.getCapabilities() + '"');
_context.peerManager().setCapabilities(key, ri.getCapabilities());
}
return;
} else if (dsm.getReplyToken() != 0) {
_context.statManager().addRateData("tunnel.dropDangerousClientTunnelMessage", 1, type);
_log.error("Dropping LS DSM w/ reply token down a tunnel for " + _client + ": " + msg);
return;
} else {
// allow DSM of our own key (used by FloodfillVerifyStoreJob)
// or other keys (used by IterativeSearchJob)
// as long as there's no reply token (we will never set a reply token but an attacker might)
((LeaseSet) dsm.getEntry()).setReceivedAsReply();
}
break;
case DeliveryStatusMessage.MESSAGE_TYPE:
case GarlicMessage.MESSAGE_TYPE:
case TunnelBuildReplyMessage.MESSAGE_TYPE:
case VariableTunnelBuildReplyMessage.MESSAGE_TYPE:
// these are safe, handled below
break;
default:
// drop it, since we should only get the above message types down
// client tunnels
_context.statManager().addRateData("tunnel.dropDangerousClientTunnelMessage", 1, type);
_log.error("Dropped dangerous message down a tunnel for " + _client + ": " + msg, new Exception("cause"));
return;
}
// switch
} else {
// expl. tunnel
switch(type) {
case DatabaseStoreMessage.MESSAGE_TYPE:
DatabaseStoreMessage dsm = (DatabaseStoreMessage) msg;
if (dsm.getReplyToken() != 0) {
_context.statManager().addRateData("tunnel.dropDangerousExplTunnelMessage", 1, type);
_log.error("Dropping DSM w/ reply token down a expl. tunnel: " + msg);
return;
}
if (dsm.getEntry().getType() == DatabaseEntry.KEY_TYPE_LEASESET)
((LeaseSet) dsm.getEntry()).setReceivedAsReply();
break;
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
case DeliveryStatusMessage.MESSAGE_TYPE:
case GarlicMessage.MESSAGE_TYPE:
case TunnelBuildReplyMessage.MESSAGE_TYPE:
case VariableTunnelBuildReplyMessage.MESSAGE_TYPE:
// these are safe, handled below
break;
default:
_context.statManager().addRateData("tunnel.dropDangerousExplTunnelMessage", 1, type);
_log.error("Dropped dangerous message down expl tunnel: " + msg, new Exception("cause"));
return;
}
// switch
}
if ((target == null) || ((tunnel == null) && (_context.routerHash().equals(target)))) {
// make sure we don't honor any remote requests directly (garlic instructions, etc)
if (type == GarlicMessage.MESSAGE_TYPE) {
// in case we're looking for replies to a garlic message (cough load tests cough)
_context.inNetMessagePool().handleReplies(msg);
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("received garlic message in the tunnel, parse it out");
_receiver.receive((GarlicMessage) msg);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("distributing inbound tunnel message into our inNetMessagePool: " + msg);
_context.inNetMessagePool().add(msg, null, null);
}
/**
**** latency measuring attack?
* } else if (_context.routerHash().equals(target)) {
* // the want to send it to a tunnel, except we are also that tunnel's gateway
* // dispatch it directly
* if (_log.shouldLog(Log.INFO))
* _log.info("distributing inbound tunnel message back out, except we are the gateway");
* TunnelGatewayMessage gw = new TunnelGatewayMessage(_context);
* gw.setMessage(msg);
* gw.setTunnelId(tunnel);
* gw.setMessageExpiration(_context.clock().now()+10*1000);
* gw.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
* _context.tunnelDispatcher().dispatch(gw);
*****
*/
} else {
// ok, they want us to send it remotely, but that'd bust our anonymity,
// so we send it out a tunnel first
// TODO use the OCMOSJ cache to pick OB tunnel we are already using?
TunnelInfo out = _context.tunnelManager().selectOutboundTunnel(_client, target);
if (out == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("no outbound tunnel to send the client message for " + _client + ": " + msg);
return;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("distributing IB tunnel msg type " + type + " back out " + out + " targetting " + target);
TunnelId outId = out.getSendTunnelId(0);
if (outId == null) {
if (_log.shouldLog(Log.ERROR))
_log.error("strange? outbound tunnel has no outboundId? " + out + " failing to distribute " + msg);
return;
}
long exp = _context.clock().now() + 20 * 1000;
if (msg.getMessageExpiration() < exp)
msg.setMessageExpiration(exp);
_context.tunnelDispatcher().dispatchOutbound(msg, outId, tunnel, target);
}
}
use of net.i2p.data.TunnelId in project i2p.i2p by i2p.
the class TunnelDispatcher method joinInbound.
/**
* We are the inbound endpoint - we created this tunnel
*
* @return success; false if Tunnel ID is a duplicate
*/
public boolean joinInbound(TunnelCreatorConfig cfg) {
if (_log.shouldLog(Log.INFO))
_log.info("Inbound built successfully: " + cfg);
if (cfg.getLength() > 1) {
TunnelParticipant participant = new TunnelParticipant(_context, new InboundEndpointProcessor(_context, cfg, _validator));
TunnelId recvId = cfg.getConfig(cfg.getLength() - 1).getReceiveTunnel();
if (_participants.putIfAbsent(recvId, participant) != null)
return false;
_context.statManager().addRateData("tunnel.joinInboundEndpoint", 1);
_context.messageHistory().tunnelJoined("inboundEndpoint", cfg);
} else {
TunnelGatewayZeroHop gw = new TunnelGatewayZeroHop(_context, cfg);
TunnelId recvId = cfg.getConfig(0).getReceiveTunnel();
if (_inboundGateways.putIfAbsent(recvId, gw) != null)
return false;
_context.statManager().addRateData("tunnel.joinInboundEndpointZeroHop", 1);
_context.messageHistory().tunnelJoined("inboundEndpointZeroHop", cfg);
}
return true;
}
use of net.i2p.data.TunnelId in project i2p.i2p by i2p.
the class TunnelDispatcher method joinOutboundEndpoint.
/**
* We are the outbound endpoint in this tunnel, and did not create it
*
* @return success; false if Tunnel ID is a duplicate
*/
public boolean joinOutboundEndpoint(HopConfig cfg) {
if (_log.shouldLog(Log.INFO))
_log.info("Joining as OBEP: " + cfg);
TunnelId recvId = cfg.getReceiveTunnel();
OutboundTunnelEndpoint endpoint = new OutboundTunnelEndpoint(_context, cfg, new HopProcessor(_context, cfg, _validator));
synchronized (_joinParticipantLock) {
if (_participatingConfig.putIfAbsent(recvId, cfg) != null)
return false;
if (_outboundEndpoints.putIfAbsent(recvId, endpoint) != null) {
_participatingConfig.remove(recvId);
return false;
}
}
_context.messageHistory().tunnelJoined("outboundEndpoint", cfg);
_context.statManager().addRateData("tunnel.joinOutboundEndpoint", 1);
if (cfg.getExpiration() > _lastParticipatingExpiration)
_lastParticipatingExpiration = cfg.getExpiration();
_leaveJob.add(cfg);
return true;
}
use of net.i2p.data.TunnelId in project i2p.i2p by i2p.
the class TunnelDispatcher method joinOutbound.
/**
* We are the outbound gateway - we created this tunnel
*
* @return success; false if Tunnel ID is a duplicate
*/
public boolean joinOutbound(TunnelCreatorConfig cfg) {
if (_log.shouldLog(Log.INFO))
_log.info("Outbound built successfully: " + cfg);
TunnelGateway gw;
if (cfg.getLength() > 1) {
TunnelGateway.QueuePreprocessor preproc = createPreprocessor(cfg);
TunnelGateway.Sender sender = new OutboundSender(_context, cfg);
TunnelGateway.Receiver receiver = new OutboundReceiver(_context, cfg);
// TunnelGateway gw = new TunnelGateway(_context, preproc, sender, receiver);
gw = new PumpedTunnelGateway(_context, preproc, sender, receiver, _pumper);
} else {
gw = new TunnelGatewayZeroHop(_context, cfg);
}
TunnelId outId = cfg.getConfig(0).getSendTunnel();
if (_outboundGateways.putIfAbsent(outId, gw) != null)
return false;
if (cfg.getLength() > 1) {
_context.statManager().addRateData("tunnel.joinOutboundGateway", 1);
_context.messageHistory().tunnelJoined("outbound", cfg);
} else {
_context.statManager().addRateData("tunnel.joinOutboundGatewayZeroHop", 1);
_context.messageHistory().tunnelJoined("outboundZeroHop", cfg);
}
return true;
}
use of net.i2p.data.TunnelId in project i2p.i2p by i2p.
the class PeerTestJob method testPeer.
/**
* Fire off the necessary jobs and messages to test the given peer
* The message is a store of the peer's RI to itself,
* with a reply token.
*/
private void testPeer(RouterInfo peer) {
TunnelInfo inTunnel = getInboundTunnelId();
if (inTunnel == null) {
_log.warn("No tunnels to get peer test replies through!");
return;
}
TunnelId inTunnelId = inTunnel.getReceiveTunnelId(0);
RouterInfo inGateway = getContext().netDb().lookupRouterInfoLocally(inTunnel.getPeer(0));
if (inGateway == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("We can't find the gateway to our inbound tunnel?! Impossible?");
return;
}
int timeoutMs = getTestTimeout();
long expiration = getContext().clock().now() + timeoutMs;
long nonce = 1 + getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE - 1);
DatabaseStoreMessage msg = buildMessage(peer, inTunnelId, inGateway.getIdentity().getHash(), nonce, expiration);
TunnelInfo outTunnel = getOutboundTunnelId();
if (outTunnel == null) {
_log.warn("No tunnels to send search out through! Something is wrong...");
return;
}
TunnelId outTunnelId = outTunnel.getSendTunnelId(0);
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Sending peer test to " + peer.getIdentity().getHash().toBase64() + " out " + outTunnel + " w/ replies through " + inTunnel);
ReplySelector sel = new ReplySelector(peer.getIdentity().getHash(), nonce, expiration);
PeerReplyFoundJob reply = new PeerReplyFoundJob(getContext(), peer, inTunnel, outTunnel);
PeerReplyTimeoutJob timeoutJob = new PeerReplyTimeoutJob(getContext(), peer, inTunnel, outTunnel, sel);
getContext().messageRegistry().registerPending(sel, reply, timeoutJob);
getContext().tunnelDispatcher().dispatchOutbound(msg, outTunnelId, null, peer.getIdentity().getHash());
}
Aggregations