use of net.i2p.data.Hash 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.Hash in project i2p.i2p by i2p.
the class TimedWeightedPriorityMessageQueue method getNext.
/**
* Grab the next message out of the next queue. This only advances
* the _nextQueue var after pushing _weighting[currentQueue] messages
* or the queue is empty. This call blocks until either a message
* becomes available or the queue is shut down.
*
* @param blockUntil expiration, or -1 if indefinite
* @return message dequeued, or null if the queue was shut down
*/
public OutNetMessage getNext(long blockUntil) {
while (_alive) {
_addedSincePassBegan = false;
for (int i = 0; i < _queue.length; i++) {
int currentQueue = (_nextQueue + i) % _queue.length;
synchronized (_queue[currentQueue]) {
for (int j = 0; j < _queue[currentQueue].size(); j++) {
OutNetMessage msg = _queue[currentQueue].get(j);
Hash to = msg.getTarget().getIdentity().getHash();
if (_chokedPeers.contains(to))
continue;
// not choked, lets push it to active
_queue[currentQueue].remove(j);
long size = msg.getMessageSize();
_bytesQueued[currentQueue] -= size;
_bytesTransferred[currentQueue] += size;
_messagesFlushed[currentQueue]++;
if (_messagesFlushed[currentQueue] >= _weighting[currentQueue]) {
_messagesFlushed[currentQueue] = 0;
_nextQueue = (currentQueue + 1) % _queue.length;
}
int sz = _queue[currentQueue].size();
_context.statManager().addRateData("udp.messageQueueSize", sz, currentQueue);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Pulling a message off queue " + currentQueue + " with " + sz + " remaining");
msg.timestamp("made active with remaining queue size " + sz);
return msg;
}
// nothing waiting, or only choked peers
_messagesFlushed[currentQueue] = 0;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nothing available on queue " + currentQueue);
}
}
long remaining = blockUntil - _context.clock().now();
if ((blockUntil > 0) && (remaining < 0)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nonblocking, or block time has expired");
return null;
}
try {
synchronized (_nextLock) {
if (!_addedSincePassBegan && _alive) {
// wait, but it doesn't hurt to loop again.
if (_log.shouldLog(Log.DEBUG))
_log.debug("Wait for activity (up to " + remaining + "ms)");
if (blockUntil < 0)
_nextLock.wait();
else
_nextLock.wait(remaining);
}
}
} catch (InterruptedException ie) {
}
}
return null;
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class UDPTransport method locked_addRemotePeerState.
private boolean locked_addRemotePeerState(PeerState peer) {
Hash remotePeer = peer.getRemotePeer();
long oldEstablishedOn = -1;
PeerState oldPeer = null;
if (remotePeer != null) {
oldPeer = _peersByIdent.put(remotePeer, peer);
if ((oldPeer != null) && (oldPeer != peer)) {
// this happens a lot
if (_log.shouldInfo())
_log.info("Peer already connected (PBID): old=" + oldPeer + " new=" + peer);
// transfer over the old state/inbound message fragments/etc
peer.loadFrom(oldPeer);
oldEstablishedOn = oldPeer.getKeyEstablishedTime();
}
}
RemoteHostId remoteId = peer.getRemoteHostId();
if (oldPeer != null) {
oldPeer.dropOutbound();
_introManager.remove(oldPeer);
_expireEvent.remove(oldPeer);
RemoteHostId oldID = oldPeer.getRemoteHostId();
if (!remoteId.equals(oldID)) {
// leak fix, remove old address
if (_log.shouldInfo())
_log.info(remotePeer + " changed address FROM " + oldID + " TO " + remoteId);
PeerState oldPeer2 = _peersByRemoteHost.remove(oldID);
// different ones in the two maps? shouldn't happen
if (oldPeer2 != oldPeer && oldPeer2 != null) {
oldPeer2.dropOutbound();
_introManager.remove(oldPeer2);
_expireEvent.remove(oldPeer2);
}
}
}
// or do we always know the IP by now?
if (remoteId.getIP() == null && _log.shouldLog(Log.WARN))
_log.warn("Add indirect: " + peer);
// don't do this twice
PeerState oldPeer2 = _peersByRemoteHost.put(remoteId, peer);
if (oldPeer2 != null && oldPeer2 != peer && oldPeer2 != oldPeer) {
// this shouldn't happen, should have been removed above
if (_log.shouldLog(Log.WARN))
_log.warn("Peer already connected (PBRH): old=" + oldPeer2 + " new=" + peer);
// transfer over the old state/inbound message fragments/etc
peer.loadFrom(oldPeer2);
oldEstablishedOn = oldPeer2.getKeyEstablishedTime();
oldPeer2.dropOutbound();
_introManager.remove(oldPeer2);
_expireEvent.remove(oldPeer2);
}
if (_log.shouldLog(Log.WARN) && !_mismatchLogged && _peersByIdent.size() != _peersByRemoteHost.size()) {
_mismatchLogged = true;
_log.warn("Size Mismatch after add: " + peer + " byIDsz = " + _peersByIdent.size() + " byHostsz = " + _peersByRemoteHost.size());
}
_activeThrottle.unchoke(peer.getRemotePeer());
markReachable(peer.getRemotePeer(), peer.isInbound());
// _context.banlist().unbanlistRouter(peer.getRemotePeer(), STYLE);
// if (SHOULD_FLOOD_PEERS)
// _flooder.addPeer(peer);
_expireEvent.add(peer);
_introManager.add(peer);
if (oldEstablishedOn > 0)
_context.statManager().addRateData("udp.alreadyConnected", oldEstablishedOn);
synchronized (_rebuildLock) {
rebuildIfNecessary();
Status status = getReachabilityStatus();
if (status != Status.OK && status != Status.IPV4_OK_IPV6_UNKNOWN && status != Status.IPV4_OK_IPV6_FIREWALLED && status != Status.IPV4_DISABLED_IPV6_OK && status != Status.IPV4_DISABLED_IPV6_UNKNOWN && status != Status.IPV4_DISABLED_IPV6_FIREWALLED && status != Status.DISCONNECTED && _reachabilityStatusUnchanged < 7) {
_testEvent.forceRunSoon(peer.isIPv6());
}
}
return true;
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class UDPTransport method bid.
public TransportBid bid(RouterInfo toAddress, long dataSize) {
if (dataSize > OutboundMessageState.MAX_MSG_SIZE) {
// NTCP max is lower, so msg will get dropped
return null;
}
Hash to = toAddress.getIdentity().calculateHash();
PeerState peer = getPeerState(to);
if (peer != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("bidding on a message to an established peer: " + peer);
if (preferUDP())
return _cachedBid[FAST_PREFERRED_BID];
else
return _cachedBid[FAST_BID];
} else {
// If we don't have a port, all is lost
if (_reachabilityStatus == Status.HOSED) {
markUnreachable(to);
return null;
}
// Validate his SSU address
RouterAddress addr = getTargetAddress(toAddress);
if (addr == null) {
markUnreachable(to);
return null;
}
// Check for supported sig type
SigType type = toAddress.getIdentity().getSigType();
if (type == null || !type.isAvailable()) {
markUnreachable(to);
return null;
}
// Can we connect to them if we are not DSA?
RouterInfo us = _context.router().getRouterInfo();
if (us != null) {
RouterIdentity id = us.getIdentity();
if (id.getSigType() != SigType.DSA_SHA1) {
String v = toAddress.getVersion();
if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0) {
markUnreachable(to);
return null;
}
}
}
if (!allowConnection())
return _cachedBid[TRANSIENT_FAIL_BID];
if (_log.shouldLog(Log.DEBUG))
_log.debug("bidding on a message to an unestablished peer: " + to);
// Try to maintain at least 5 peers (30 for v6) so we can determine our IP address and
// we have a selection to run peer tests with.
// If we are firewalled, and we don't have enough peers that volunteered to
// also introduce us, also bid aggressively so we are preferred over NTCP.
// (Otherwise we only talk UDP to those that are firewalled, and we will
// never get any introducers)
int count = _peersByIdent.size();
if (alwaysPreferUDP()) {
return _cachedBid[SLOW_PREFERRED_BID];
} else if (count < _min_peers || (_haveIPv6Address && count < _min_v6_peers) || (introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL)) {
// TODO After some time, decide that UDP is blocked/broken and return TRANSIENT_FAIL_BID?
if (_context.random().nextInt(4) == 0)
return _cachedBid[SLOWEST_BID];
else
return _cachedBid[SLOW_PREFERRED_BID];
} else if (preferUDP()) {
return _cachedBid[SLOW_BID];
} else if (haveCapacity()) {
if (addr.getCost() > DEFAULT_COST)
return _cachedBid[SLOWEST_COST_BID];
else
return _cachedBid[SLOWEST_BID];
} else {
if (addr.getCost() > DEFAULT_COST)
return _cachedBid[NEAR_CAPACITY_COST_BID];
else
return _cachedBid[NEAR_CAPACITY_BID];
}
}
}
use of net.i2p.data.Hash in project i2p.i2p by i2p.
the class UDPTransport method messageReceived.
/**
* infinite loop
* public RouterAddress getCurrentAddress() {
* if (needsRebuild())
* rebuildExternalAddress(false);
* return super.getCurrentAddress();
* }
**
*/
@Override
public void messageReceived(I2NPMessage inMsg, RouterIdentity remoteIdent, Hash remoteIdentHash, long msToReceive, int bytesReceived) {
if (inMsg.getType() == DatabaseStoreMessage.MESSAGE_TYPE) {
DatabaseStoreMessage dsm = (DatabaseStoreMessage) inMsg;
DatabaseEntry entry = dsm.getEntry();
if (entry == null)
return;
if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO && ((RouterInfo) entry).getNetworkId() != _networkID) {
// this is pre-0.6.1.10, so it isn't going to happen any more
/*
if (remoteIdentHash != null) {
_context.banlist().banlistRouter(remoteIdentHash, "Sent us a peer from the wrong network");
dropPeer(remoteIdentHash);
if (_log.shouldLog(Log.ERROR))
_log.error("Dropping the peer " + remoteIdentHash
+ " because they are in the wrong net");
} else if (remoteIdent != null) {
_context.banlist().banlistRouter(remoteIdent.calculateHash(), "Sent us a peer from the wrong network");
dropPeer(remoteIdent.calculateHash());
if (_log.shouldLog(Log.ERROR))
_log.error("Dropping the peer " + remoteIdent.calculateHash()
+ " because they are in the wrong net");
}
*/
Hash peerHash = entry.getHash();
PeerState peer = getPeerState(peerHash);
if (peer != null) {
RemoteHostId remote = peer.getRemoteHostId();
_dropList.add(remote);
_context.statManager().addRateData("udp.dropPeerDroplist", 1);
_context.simpleTimer2().addEvent(new RemoveDropList(remote), DROPLIST_PERIOD);
}
markUnreachable(peerHash);
_context.banlist().banlistRouter(peerHash, "Part of the wrong network, version = " + ((RouterInfo) entry).getVersion());
// _context.banlist().banlistRouter(peerHash, "Part of the wrong network", STYLE);
if (peer != null)
sendDestroy(peer);
dropPeer(peerHash, false, "wrong network");
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping the peer " + peerHash + " because they are in the wrong net: " + entry);
return;
} else {
if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received an RI from the same net");
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received a leaseSet: " + dsm);
}
}
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received another message: " + inMsg.getClass().getName());
}
PeerState peer = getPeerState(remoteIdentHash);
super.messageReceived(inMsg, remoteIdent, remoteIdentHash, msToReceive, bytesReceived);
if (peer != null)
peer.expireInboundMessages();
}
Aggregations