Search in sources :

Example 76 with Hash

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);
    }
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash) TunnelId(net.i2p.data.TunnelId)

Example 77 with Hash

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) Hash(net.i2p.data.Hash)

Example 78 with Hash

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;
}
Also used : Status(net.i2p.router.CommSystemFacade.Status) Hash(net.i2p.data.Hash)

Example 79 with Hash

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];
        }
    }
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) RouterIdentity(net.i2p.data.router.RouterIdentity) RouterAddress(net.i2p.data.router.RouterAddress) Hash(net.i2p.data.Hash) SigType(net.i2p.crypto.SigType)

Example 80 with Hash

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();
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) DatabaseEntry(net.i2p.data.DatabaseEntry) Hash(net.i2p.data.Hash)

Aggregations

Hash (net.i2p.data.Hash)235 RouterInfo (net.i2p.data.router.RouterInfo)45 ArrayList (java.util.ArrayList)29 TunnelId (net.i2p.data.TunnelId)20 Destination (net.i2p.data.Destination)18 HashSet (java.util.HashSet)17 ConvertToHash (net.i2p.util.ConvertToHash)17 IOException (java.io.IOException)16 TunnelInfo (net.i2p.router.TunnelInfo)15 DataFormatException (net.i2p.data.DataFormatException)14 Properties (java.util.Properties)13 Date (java.util.Date)12 DatabaseEntry (net.i2p.data.DatabaseEntry)11 SessionKey (net.i2p.data.SessionKey)11 RouterAddress (net.i2p.data.router.RouterAddress)11 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)9 I2NPMessage (net.i2p.data.i2np.I2NPMessage)9 Job (net.i2p.router.Job)9 OutNetMessage (net.i2p.router.OutNetMessage)9 TunnelPoolSettings (net.i2p.router.TunnelPoolSettings)8