Search in sources :

Example 1 with RouterIdentity

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

the class EstablishmentManager method handleCompletelyEstablished.

/**
 * ok, fully received, add it to the established cons and queue up a
 * netDb store to them
 */
private void handleCompletelyEstablished(InboundEstablishState state) {
    if (state.isComplete())
        return;
    RouterIdentity remote = state.getConfirmedIdentity();
    PeerState peer = new PeerState(_context, _transport, state.getSentIP(), state.getSentPort(), remote.calculateHash(), true);
    peer.setCurrentCipherKey(state.getCipherKey());
    peer.setCurrentMACKey(state.getMACKey());
    peer.setWeRelayToThemAs(state.getSentRelayTag());
    // Lookup the peer's MTU from the netdb, since it isn't included in the protocol setup (yet)
    // TODO if we don't have RI then we will get it shortly, but too late.
    // Perhaps netdb should notify transport when it gets a new RI...
    RouterInfo info = _context.netDb().lookupRouterInfoLocally(remote.calculateHash());
    if (info != null) {
        RouterAddress addr = _transport.getTargetAddress(info);
        if (addr != null) {
            String smtu = addr.getOption(UDPAddress.PROP_MTU);
            if (smtu != null) {
                try {
                    boolean isIPv6 = state.getSentIP().length == 16;
                    int mtu = MTU.rectify(isIPv6, Integer.parseInt(smtu));
                    peer.setHisMTU(mtu);
                } catch (NumberFormatException nfe) {
                }
            }
        }
    }
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Handle completely established (inbound): " + state + " - " + peer.getRemotePeer());
    // if (true) // for now, only support direct
    // peer.setRemoteRequiresIntroduction(false);
    _transport.addRemotePeerState(peer);
    boolean isIPv6 = state.getSentIP().length == 16;
    _transport.inboundConnectionReceived(isIPv6);
    _transport.setIP(remote.calculateHash(), state.getSentIP());
    _context.statManager().addRateData("udp.inboundEstablishTime", state.getLifetime());
    sendInboundComplete(peer);
    OutNetMessage msg;
    while ((msg = state.getNextQueuedMessage()) != null) {
        if (_context.clock().now() - Router.CLOCK_FUDGE_FACTOR > msg.getExpiration()) {
            msg.timestamp("took too long but established...");
            _transport.failed(msg, "Took too long to establish, but it was established");
        } else {
            msg.timestamp("session fully established and sent");
            _transport.send(msg);
        }
    }
    state.complete();
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) RouterIdentity(net.i2p.data.router.RouterIdentity) RouterInfo(net.i2p.data.router.RouterInfo) RouterAddress(net.i2p.data.router.RouterAddress)

Example 2 with RouterIdentity

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

the class EstablishmentManager method handleCompletelyEstablished.

/**
 * ok, fully received, add it to the established cons and send any
 * queued messages
 *
 * @return the new PeerState
 */
private PeerState handleCompletelyEstablished(OutboundEstablishState state) {
    if (state.complete()) {
        RouterIdentity rem = state.getRemoteIdentity();
        if (rem != null)
            return _transport.getPeerState(rem.getHash());
    }
    long now = _context.clock().now();
    RouterIdentity remote = state.getRemoteIdentity();
    // only if == state
    RemoteHostId claimed = state.getClaimedAddress();
    if (claimed != null)
        _outboundByClaimedAddress.remove(claimed, state);
    _outboundByHash.remove(remote.calculateHash(), state);
    PeerState peer = new PeerState(_context, _transport, state.getSentIP(), state.getSentPort(), remote.calculateHash(), false);
    peer.setCurrentCipherKey(state.getCipherKey());
    peer.setCurrentMACKey(state.getMACKey());
    peer.setTheyRelayToUsAs(state.getReceivedRelayTag());
    int mtu = state.getRemoteAddress().getMTU();
    if (mtu > 0)
        peer.setHisMTU(mtu);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Handle completely established (outbound): " + state + " - " + peer.getRemotePeer());
    _transport.addRemotePeerState(peer);
    _transport.setIP(remote.calculateHash(), state.getSentIP());
    _context.statManager().addRateData("udp.outboundEstablishTime", state.getLifetime());
    DatabaseStoreMessage dbsm = null;
    if (!state.isFirstMessageOurDSM()) {
        dbsm = getOurInfo();
    } else if (_log.shouldLog(Log.INFO)) {
        _log.info("Skipping publish: " + state);
    }
    List<OutNetMessage> msgs = new ArrayList<OutNetMessage>(8);
    OutNetMessage msg;
    while ((msg = state.getNextQueuedMessage()) != null) {
        if (now - Router.CLOCK_FUDGE_FACTOR > msg.getExpiration()) {
            msg.timestamp("took too long but established...");
            _transport.failed(msg, "Took too long to establish, but it was established");
        } else {
            msg.timestamp("session fully established and sent");
            msgs.add(msg);
        }
    }
    _transport.send(dbsm, msgs, peer);
    return peer;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) RouterIdentity(net.i2p.data.router.RouterIdentity) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) ArrayList(java.util.ArrayList)

Example 3 with RouterIdentity

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

the class EstablishmentManager method establish.

/**
 *  @param queueIfMaxExceeded true normally, false if called from locked_admit so we don't loop
 *  @since 0.9.2
 */
private void establish(OutNetMessage msg, boolean queueIfMaxExceeded) {
    RouterInfo toRouterInfo = msg.getTarget();
    RouterAddress ra = _transport.getTargetAddress(toRouterInfo);
    if (ra == null) {
        _transport.failed(msg, "Remote peer has no address, cannot establish");
        return;
    }
    RouterIdentity toIdentity = toRouterInfo.getIdentity();
    Hash toHash = toIdentity.calculateHash();
    if (toRouterInfo.getNetworkId() != _networkID) {
        _context.banlist().banlistRouter(toHash);
        _transport.markUnreachable(toHash);
        _transport.failed(msg, "Remote peer is on the wrong network, cannot establish");
        return;
    }
    UDPAddress addr = new UDPAddress(ra);
    RemoteHostId maybeTo = null;
    InetAddress remAddr = addr.getHostAddress();
    int port = addr.getPort();
    // claimed address (which we won't be using if indirect)
    if (remAddr != null && port > 0 && port <= 65535) {
        maybeTo = new RemoteHostId(remAddr.getAddress(), port);
        if ((!_transport.isValid(maybeTo.getIP())) || (Arrays.equals(maybeTo.getIP(), _transport.getExternalIP()) && !_transport.allowLocal())) {
            _transport.failed(msg, "Remote peer's IP isn't valid");
            _transport.markUnreachable(toHash);
            // _context.banlist().banlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address", UDPTransport.STYLE);
            _context.statManager().addRateData("udp.establishBadIP", 1);
            return;
        }
        InboundEstablishState inState = _inboundStates.get(maybeTo);
        if (inState != null) {
            // we have an inbound establishment in progress, queue it there instead
            synchronized (inState) {
                switch(inState.getState()) {
                    case IB_STATE_UNKNOWN:
                    case IB_STATE_REQUEST_RECEIVED:
                    case IB_STATE_CREATED_SENT:
                    case IB_STATE_CONFIRMED_PARTIALLY:
                    case IB_STATE_CONFIRMED_COMPLETELY:
                        // queue it
                        inState.addMessage(msg);
                        if (_log.shouldLog(Log.WARN))
                            _log.debug("OB msg queued to IES");
                        break;
                    case IB_STATE_COMPLETE:
                        // race, send it out (but don't call _transport.send() again and risk a loop)
                        _transport.sendIfEstablished(msg);
                        break;
                    case IB_STATE_FAILED:
                        // race, failed
                        _transport.failed(msg, "OB msg failed during IB establish");
                        break;
                }
            }
            return;
        }
    }
    RemoteHostId to;
    boolean isIndirect = addr.getIntroducerCount() > 0 || maybeTo == null;
    if (isIndirect) {
        to = new RemoteHostId(toHash);
    } else {
        to = maybeTo;
    }
    OutboundEstablishState state = null;
    int deferred = 0;
    boolean rejected = false;
    int queueCount = 0;
    state = _outboundStates.get(to);
    if (state == null) {
        state = _outboundByHash.get(toHash);
        if (state != null && _log.shouldLog(Log.INFO))
            _log.info("Found by hash: " + state);
    }
    if (state == null) {
        if (queueIfMaxExceeded && _outboundStates.size() >= getMaxConcurrentEstablish()) {
            if (_queuedOutbound.size() >= MAX_QUEUED_OUTBOUND && !_queuedOutbound.containsKey(to)) {
                rejected = true;
            } else {
                List<OutNetMessage> newQueued = new ArrayList<OutNetMessage>(MAX_QUEUED_PER_PEER);
                List<OutNetMessage> queued = _queuedOutbound.putIfAbsent(to, newQueued);
                if (queued == null) {
                    queued = newQueued;
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("Queueing outbound establish to " + to + ", increase " + PROP_MAX_CONCURRENT_ESTABLISH);
                }
                // There are still races possible but this should prevent AIOOBE and NPE
                synchronized (queued) {
                    queueCount = queued.size();
                    if (queueCount < MAX_QUEUED_PER_PEER) {
                        queued.add(msg);
                        // increment for the stat below
                        queueCount++;
                    } else {
                        rejected = true;
                    }
                    deferred = _queuedOutbound.size();
                }
            }
        } else {
            // must have a valid session key
            byte[] keyBytes = addr.getIntroKey();
            if (keyBytes == null) {
                _transport.markUnreachable(toHash);
                _transport.failed(msg, "Peer has no key, cannot establish");
                return;
            }
            SessionKey sessionKey;
            try {
                sessionKey = new SessionKey(keyBytes);
            } catch (IllegalArgumentException iae) {
                _transport.markUnreachable(toHash);
                _transport.failed(msg, "Peer has bad key, cannot establish");
                return;
            }
            boolean allowExtendedOptions = VersionComparator.comp(toRouterInfo.getVersion(), VERSION_ALLOW_EXTENDED_OPTIONS) >= 0 && !_context.getBooleanProperty(PROP_DISABLE_EXT_OPTS);
            // w/o ext options, it's always 'requested', no need to set
            // don't ask if they are indirect
            boolean requestIntroduction = allowExtendedOptions && !isIndirect && _transport.introducersMaybeRequired();
            state = new OutboundEstablishState(_context, maybeTo, to, toIdentity, allowExtendedOptions, requestIntroduction, sessionKey, addr, _transport.getDHFactory());
            OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state);
            boolean isNew = oldState == null;
            if (isNew) {
                if (isIndirect && maybeTo != null)
                    _outboundByClaimedAddress.put(maybeTo, state);
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("Adding new " + state);
            } else {
                // whoops, somebody beat us to it, throw out the state we just created
                state = oldState;
            }
        }
    }
    if (state != null) {
        state.addMessage(msg);
        List<OutNetMessage> queued = _queuedOutbound.remove(to);
        if (queued != null) {
            // see comments above
            synchronized (queued) {
                for (OutNetMessage m : queued) {
                    state.addMessage(m);
                }
            }
        }
    }
    if (rejected) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Too many pending, rejecting outbound establish to " + to);
        _transport.failed(msg, "Too many pending outbound connections");
        _context.statManager().addRateData("udp.establishRejected", deferred);
        return;
    }
    if (queueCount >= MAX_QUEUED_PER_PEER) {
        _transport.failed(msg, "Too many pending messages for the given peer");
        _context.statManager().addRateData("udp.establishOverflow", queueCount, deferred);
        return;
    }
    if (deferred > 0)
        msg.timestamp("too many deferred establishers");
    else if (state != null)
        msg.timestamp("establish state already waiting");
    notifyActivity();
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) RouterIdentity(net.i2p.data.router.RouterIdentity) ArrayList(java.util.ArrayList) RouterAddress(net.i2p.data.router.RouterAddress) Hash(net.i2p.data.Hash) OutNetMessage(net.i2p.router.OutNetMessage) SessionKey(net.i2p.data.SessionKey) InetAddress(java.net.InetAddress)

Example 4 with RouterIdentity

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

the class EstablishState method readAliceRouterIdentity.

/**
 * We are Bob. We have received enough of message #3 from Alice
 * to get Alice's RouterIdentity.
 *
 * _aliceIdentSize must be set.
 * _sz_aliceIdent_tsA_padding_aliceSig must contain at least 2 + _aliceIdentSize bytes.
 *
 * Sets _aliceIdent so that we
 * may determine the signature and padding sizes.
 *
 * After all of message #3 is received including the signature and
 * padding, verifyIdentity() must be called.
 *
 *  State must be IB_GOT_RI_SIZE.
 *  Caller must synch.
 *
 * @since 0.9.16 pulled out of verifyInbound()
 */
private void readAliceRouterIdentity() {
    byte[] b = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
    try {
        int sz = _aliceIdentSize;
        if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE || sz > b.length - 2) {
            _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
            fail("size is invalid", new Exception("size is " + sz));
            return;
        }
        RouterIdentity alice = new RouterIdentity();
        ByteArrayInputStream bais = new ByteArrayInputStream(b, 2, sz);
        alice.readBytes(bais);
        _aliceIdent = alice;
    } catch (IOException ioe) {
        _context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
        fail("Error verifying peer", ioe);
    } catch (DataFormatException dfe) {
        _context.statManager().addRateData("ntcp.invalidInboundDFE", 1);
        fail("Error verifying peer", dfe);
    }
}
Also used : DataFormatException(net.i2p.data.DataFormatException) ByteArrayInputStream(java.io.ByteArrayInputStream) RouterIdentity(net.i2p.data.router.RouterIdentity) IOException(java.io.IOException) DataFormatException(net.i2p.data.DataFormatException) IOException(java.io.IOException) UnknownHostException(java.net.UnknownHostException)

Example 5 with RouterIdentity

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

the class EventPumper method processRead.

/**
 *  OP_READ will always be set before this is called.
 *  This method will disable the interest if no more reads remain because of inbound bandwidth throttling.
 *  High-frequency path in thread.
 */
private void processRead(SelectionKey key) {
    NTCPConnection con = (NTCPConnection) key.attachment();
    ByteBuffer buf = acquireBuf();
    try {
        int read = con.getChannel().read(buf);
        if (read < 0) {
            // _context.statManager().addRateData("ntcp.readEOF", 1);
            if (con.isInbound() && con.getMessagesReceived() <= 0) {
                InetAddress addr = con.getChannel().socket().getInetAddress();
                int count;
                if (addr != null) {
                    byte[] ip = addr.getAddress();
                    ByteArray ba = new ByteArray(ip);
                    count = _blockedIPs.increment(ba);
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("Blocking IP " + Addresses.toString(ip) + " with count " + count + ": " + con);
                } else {
                    count = 1;
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("EOF on inbound before receiving any: " + con);
                }
                _context.statManager().addRateData("ntcp.dropInboundNoMessage", count);
            } else {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("EOF on " + con);
            }
            con.close();
            releaseBuf(buf);
        } else if (read == 0) {
            // if (_log.shouldLog(Log.DEBUG))
            // _log.debug("nothing to read for " + con + ", but stay interested");
            // stay interested
            // key.interestOps(key.interestOps() | SelectionKey.OP_READ);
            releaseBuf(buf);
            // workaround for channel stuck returning 0 all the time, causing 100% CPU
            int consec = con.gotZeroRead();
            if (consec >= 5) {
                _context.statManager().addRateData("ntcp.zeroReadDrop", 1);
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Fail safe zero read close " + con);
                con.close();
            } else {
                _context.statManager().addRateData("ntcp.zeroRead", consec);
                if (_log.shouldLog(Log.INFO))
                    _log.info("nothing to read for " + con + ", but stay interested");
            }
        } else {
            // clear counter for workaround above
            con.clearZeroRead();
            // ZERO COPY. The buffer will be returned in Reader.processRead()
            buf.flip();
            // con, buf);
            FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(read, "NTCP read");
            if (req.getPendingRequested() > 0) {
                // rare since we generally don't throttle inbound
                key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
                // if (_log.shouldLog(Log.DEBUG))
                // _log.debug("bw throttled reading for " + con + ", so we don't want to read anymore");
                _context.statManager().addRateData("ntcp.queuedRecv", read);
                con.queuedRecv(buf, req);
            } else {
                // fully allocated
                // if (_log.shouldLog(Log.DEBUG))
                // _log.debug("not bw throttled reading for " + con);
                // stay interested
                // key.interestOps(key.interestOps() | SelectionKey.OP_READ);
                con.recv(buf);
                _context.statManager().addRateData("ntcp.read", read);
            }
        }
    } catch (CancelledKeyException cke) {
        releaseBuf(buf);
        if (_log.shouldLog(Log.WARN))
            _log.warn("error reading on " + con, cke);
        con.close();
        _context.statManager().addRateData("ntcp.readError", 1);
    } catch (IOException ioe) {
        // common, esp. at outbound connect time
        releaseBuf(buf);
        if (con.isInbound() && con.getMessagesReceived() <= 0) {
            InetAddress addr = con.getChannel().socket().getInetAddress();
            int count;
            if (addr != null) {
                byte[] ip = addr.getAddress();
                ByteArray ba = new ByteArray(ip);
                count = _blockedIPs.increment(ba);
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Blocking IP " + Addresses.toString(ip) + " with count " + count + ": " + con);
            } else {
                count = 1;
                if (_log.shouldLog(Log.WARN))
                    _log.warn("IOE on inbound before receiving any: " + con);
            }
            _context.statManager().addRateData("ntcp.dropInboundNoMessage", count);
        } else {
            if (_log.shouldLog(Log.INFO))
                _log.info("error reading on " + con, ioe);
        }
        if (con.isEstablished()) {
            _context.statManager().addRateData("ntcp.readError", 1);
        } else {
            // Usually "connection reset by peer", probably a conn limit rejection?
            // although it could be a read failure during the DH handshake
            // Same stat as in processConnect()
            _context.statManager().addRateData("ntcp.connectFailedTimeoutIOE", 1);
            RouterIdentity rem = con.getRemotePeer();
            if (rem != null && !con.isInbound())
                _transport.markUnreachable(rem.calculateHash());
        }
        con.close();
    } catch (NotYetConnectedException nyce) {
        releaseBuf(buf);
        // ???
        key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
        if (_log.shouldLog(Log.WARN))
            _log.warn("error reading on " + con, nyce);
    }
}
Also used : CancelledKeyException(java.nio.channels.CancelledKeyException) RouterIdentity(net.i2p.data.router.RouterIdentity) ByteArray(net.i2p.data.ByteArray) IOException(java.io.IOException) NotYetConnectedException(java.nio.channels.NotYetConnectedException) ByteBuffer(java.nio.ByteBuffer) InetAddress(java.net.InetAddress)

Aggregations

RouterIdentity (net.i2p.data.router.RouterIdentity)17 RouterInfo (net.i2p.data.router.RouterInfo)10 IOException (java.io.IOException)6 DataFormatException (net.i2p.data.DataFormatException)5 Hash (net.i2p.data.Hash)5 RouterAddress (net.i2p.data.router.RouterAddress)5 SigType (net.i2p.crypto.SigType)4 OutNetMessage (net.i2p.router.OutNetMessage)4 Certificate (net.i2p.data.Certificate)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InetAddress (java.net.InetAddress)2 ArrayList (java.util.ArrayList)2 KeyCertificate (net.i2p.data.KeyCertificate)2 PrivateKey (net.i2p.data.PrivateKey)2 PublicKey (net.i2p.data.PublicKey)2 SigningPrivateKey (net.i2p.data.SigningPrivateKey)2 SigningPublicKey (net.i2p.data.SigningPublicKey)2 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)2 BufferedInputStream (java.io.BufferedInputStream)1 BufferedOutputStream (java.io.BufferedOutputStream)1