From 55869af2cc954f7a0f712946337c63f1e58b1848 Mon Sep 17 00:00:00 2001 From: jrandom Date: Fri, 30 Sep 2005 07:17:56 +0000 Subject: [PATCH] 2005-09-29 jrandom * Support noreseed.i2p in addition to .i2pnoreseed for disabling automatic reseeding - useful on OSes that make it hard to create dot files. Thanks Complication (and anon)! * Fixed the installer version string (thanks Frontier!) * Added cleaner rejection of invalid IP addresses, shitlist those who send us invalid IP addresses, verify again that we are not sending invalid IP addresses, and log an error if it happens. (Thanks Complication, ptm, and adab!) --- .../i2p/router/web/RouterConsoleRunner.java | 16 +++++- history.txt | 12 +++- installer/install.xml | 2 +- .../src/net/i2p/router/RouterVersion.java | 4 +- .../i2p/router/transport/udp/ACKSender.java | 2 +- .../transport/udp/EstablishmentManager.java | 15 ++++- .../transport/udp/InboundEstablishState.java | 6 ++ .../transport/udp/IntroductionManager.java | 2 +- .../transport/udp/OutboundEstablishState.java | 32 ++++++----- .../udp/OutboundMessageFragments.java | 2 +- .../router/transport/udp/PacketBuilder.java | 29 +++++++--- .../router/transport/udp/PeerTestManager.java | 2 +- .../router/transport/udp/UDPPacketReader.java | 2 +- .../router/transport/udp/UDPTransport.java | 57 +++++++++++-------- 14 files changed, 122 insertions(+), 61 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index 3625e050e..ede14994d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -73,10 +73,20 @@ public class RouterConsoleRunner { t.printStackTrace(); } + // we check the i2p installation directory (.) for a flag telling us not to reseed, + // but also check the home directory for that flag too, since new users installing i2p + // don't have an installation directory that they can put the flag in yet. File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed"); - if (!noReseedFile.exists()) { - RouterContext ctx = (RouterContext)RouterContext.listContexts().get(0); - if (ctx.netDb().getKnownRouters() < 15) { + File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p"); + File noReseedFileAlt2 = new File(".i2pnoreseed"); + File noReseedFileAlt3 = new File("noreseed.i2p"); + if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) { + File netDb = new File("netDb"); + // sure, some of them could be "my.info" or various leaseSet- files, but chances are, + // if someone has those files, they've already been seeded (at least enough to let them + // get i2p started - they can reseed later in the web console) + String names[] = (netDb.exists() ? netDb.list() : null); + if ( (names == null) || (names.length < 15) ) { ReseedHandler.requestReseed(); } } diff --git a/history.txt b/history.txt index f17816f96..f252c24be 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,14 @@ -$Id: history.txt,v 1.269 2005/09/28 04:17:55 jrandom Exp $ +$Id: history.txt,v 1.270 2005/09/29 14:19:23 jrandom Exp $ + +2005-09-29 jrandom + * Support noreseed.i2p in addition to .i2pnoreseed for disabling automatic + reseeding - useful on OSes that make it hard to create dot files. + Thanks Complication (and anon)! + * Fixed the installer version string (thanks Frontier!) + * Added cleaner rejection of invalid IP addresses, shitlist those who send + us invalid IP addresses, verify again that we are not sending invalid IP + addresses, and log an error if it happens. (Thanks Complication, ptm, + and adab!) * 2005-09-29 0.6.1 released diff --git a/installer/install.xml b/installer/install.xml index d045b43bb..3af1affea 100644 --- a/installer/install.xml +++ b/installer/install.xml @@ -4,7 +4,7 @@ i2p - 0.6.0.6 + 0.6.1 diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a063803cc..56811bb09 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.249 $ $Date: 2005/09/28 04:17:54 $"; + public final static String ID = "$Revision: 1.250 $ $Date: 2005/09/29 14:19:23 $"; public final static String VERSION = "0.6.1"; - public final static long BUILD = 0; + public final static long BUILD = 1; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/transport/udp/ACKSender.java b/router/java/src/net/i2p/router/transport/udp/ACKSender.java index d34d0cfa5..b9e189721 100644 --- a/router/java/src/net/i2p/router/transport/udp/ACKSender.java +++ b/router/java/src/net/i2p/router/transport/udp/ACKSender.java @@ -29,7 +29,7 @@ public class ACKSender implements Runnable { _log = ctx.logManager().getLog(ACKSender.class); _transport = transport; _peersToACK = new ArrayList(4); - _builder = new PacketBuilder(_context); + _builder = new PacketBuilder(_context, transport); _alive = true; _context.statManager().createRateStat("udp.sendACKCount", "how many ack messages were sent to a peer", "udp", new long[] { 60*1000, 60*60*1000 }); _context.statManager().createRateStat("udp.ackFrequency", "how long ago did we send an ACK to this peer?", "udp", new long[] { 60*1000, 60*60*1000 }); diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index 6bd01a018..77bf777e0 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -52,7 +52,7 @@ public class EstablishmentManager { _context = ctx; _log = ctx.logManager().getLog(EstablishmentManager.class); _transport = transport; - _builder = new PacketBuilder(ctx); + _builder = new PacketBuilder(ctx, transport); _inboundStates = new HashMap(32); _outboundStates = new HashMap(32); _queuedOutbound = new HashMap(32); @@ -130,6 +130,7 @@ public class EstablishmentManager { if (!_transport.isValid(to.getIP())) { _transport.failed(msg); + _context.shitlist().shitlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address"); return; } @@ -529,8 +530,13 @@ public class EstablishmentManager { if (!valid) // validate clears fields on failure return; + if (!_transport.isValid(state.getReceivedIP()) || !_transport.isValid(state.getRemoteHostId().getIP())) { + state.fail(); + return; + } + // gives us the opportunity to "detect" our external addr - _transport.externalAddressReceived(state.getReceivedIP(), state.getReceivedPort()); + _transport.externalAddressReceived(state.getRemoteIdentity().calculateHash(), state.getReceivedIP(), state.getReceivedPort()); // signs if we havent signed yet state.prepareSessionConfirmed(); @@ -573,6 +579,9 @@ public class EstablishmentManager { _context.statManager().addRateData("udp.inboundEstablishFailedState", cur.getState(), cur.getLifetime()); if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing expired inbound state"); + } else if (cur.getState() == InboundEstablishState.STATE_FAILED) { + iter.remove(); + _context.statManager().addRateData("udp.inboundEstablishFailedState", cur.getState(), cur.getLifetime()); } else { if (cur.getNextSendTime() <= now) { // our turn... @@ -619,6 +628,8 @@ public class EstablishmentManager { _log.warn("why are we confirmed with no identity? " + inboundState); break; } + case InboundEstablishState.STATE_FAILED: + break; // already removed; case InboundEstablishState.STATE_UNKNOWN: // fallthrough default: // wtf diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java index be9219f19..bd2c7a5cc 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java @@ -65,6 +65,8 @@ public class InboundEstablishState { public static final int STATE_CONFIRMED_PARTIALLY = 3; /** we have completely received all of the confirmation packets */ public static final int STATE_CONFIRMED_COMPLETELY = 4; + /** we are explicitly failing it */ + public static final int STATE_FAILED = 5; public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort) { _context = ctx; @@ -128,6 +130,10 @@ public class InboundEstablishState { return _sentY; } + public synchronized void fail() { + _currentState = STATE_FAILED; + } + public synchronized long getSentRelayTag() { return _sentRelayTag; } public synchronized void setSentRelayTag(long tag) { _sentRelayTag = tag; } public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; } diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index db7e36123..6b47b7fb0 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -23,7 +23,7 @@ public class IntroductionManager { _context = ctx; _log = ctx.logManager().getLog(IntroductionManager.class); _transport = transport; - _builder = new PacketBuilder(ctx); + _builder = new PacketBuilder(ctx, transport); _outbound = Collections.synchronizedMap(new HashMap(128)); _inbound = new ArrayList(128); ctx.statManager().createRateStat("udp.receiveRelayIntro", "How often we get a relayed request for us to talk to someone?", "udp", new long[] { 60*1000, 5*60*1000, 10*60*1000 }); diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index d80e2a3d6..b160b4ceb 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -198,24 +198,28 @@ public class OutboundEstablishState { } else { if (_log.shouldLog(Log.WARN)) _log.warn("Session created failed validation, clearing state for " + _remoteHostId.toString()); - _receivedY = null; - _aliceIP = null; - _receivedRelayTag = 0; - _receivedSignedOnTime = -1; - _receivedEncryptedSignature = null; - _receivedIV = null; - _receivedSignature = null; - - if ( (_currentState == STATE_UNKNOWN) || - (_currentState == STATE_REQUEST_SENT) || - (_currentState == STATE_CREATED_RECEIVED) ) - _currentState = STATE_REQUEST_SENT; - - _nextSend = _context.clock().now(); + fail(); return false; } } + public synchronized void fail() { + _receivedY = null; + _aliceIP = null; + _receivedRelayTag = 0; + _receivedSignedOnTime = -1; + _receivedEncryptedSignature = null; + _receivedIV = null; + _receivedSignature = null; + + if ( (_currentState == STATE_UNKNOWN) || + (_currentState == STATE_REQUEST_SENT) || + (_currentState == STATE_CREATED_RECEIVED) ) + _currentState = STATE_REQUEST_SENT; + + _nextSend = _context.clock().now(); + } + private void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException { if (_sessionKey != null) return; _keyBuilder.setPeerPublicValue(_receivedY); diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java index 662498a05..3a8691021 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java @@ -48,7 +48,7 @@ public class OutboundMessageFragments { _throttle = throttle; _activeMessages = new ArrayList(MAX_ACTIVE); _nextPacketMessage = 0; - _builder = new PacketBuilder(ctx); + _builder = new PacketBuilder(ctx, transport); _alive = true; _allowExcess = false; _context.statManager().createRateStat("udp.sendVolleyTime", "Long it takes to send a full volley", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index f8ec0a0bc..73ae93b31 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -25,13 +25,15 @@ import net.i2p.util.Log; public class PacketBuilder { private I2PAppContext _context; private Log _log; + private UDPTransport _transport; private static final ByteCache _ivCache = ByteCache.getInstance(64, UDPPacket.IV_SIZE); private static final ByteCache _hmacCache = ByteCache.getInstance(64, Hash.HASH_LENGTH); private static final ByteCache _blockCache = ByteCache.getInstance(64, 16); - public PacketBuilder(I2PAppContext ctx) { + public PacketBuilder(I2PAppContext ctx, UDPTransport transport) { _context = ctx; + _transport = transport; _log = ctx.logManager().getLog(PacketBuilder.class); } @@ -224,13 +226,20 @@ public class PacketBuilder { DataHelper.toLong(data, off, 4, now); off += 4; + byte sentIP[] = state.getSentIP(); + if ( (sentIP == null) || (sentIP.length <= 0) || ( (_transport != null) && (!_transport.isValid(sentIP)) ) ) { + if (_log.shouldLog(Log.ERROR)) + _log.error("How did our sent IP become invalid? " + state); + state.fail(); + return null; + } // now for the body System.arraycopy(state.getSentY(), 0, data, off, state.getSentY().length); off += state.getSentY().length; - DataHelper.toLong(data, off, 1, state.getSentIP().length); + DataHelper.toLong(data, off, 1, sentIP.length); off += 1; - System.arraycopy(state.getSentIP(), 0, data, off, state.getSentIP().length); - off += state.getSentIP().length; + System.arraycopy(sentIP, 0, data, off, sentIP.length); + off += sentIP.length; DataHelper.toLong(data, off, 2, state.getSentPort()); off += 2; DataHelper.toLong(data, off, 4, state.getSentRelayTag()); @@ -249,7 +258,7 @@ public class PacketBuilder { if (_log.shouldLog(Log.DEBUG)) { StringBuffer buf = new StringBuffer(128); buf.append("Sending sessionCreated:"); - buf.append(" AliceIP: ").append(Base64.encode(state.getSentIP())); + buf.append(" AliceIP: ").append(Base64.encode(sentIP)); buf.append(" AlicePort: ").append(state.getSentPort()); buf.append(" BobIP: ").append(Base64.encode(state.getReceivedOurIP())); buf.append(" BobPort: ").append(externalPort); @@ -294,9 +303,13 @@ public class PacketBuilder { */ public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { UDPPacket packet = UDPPacket.acquire(_context); + byte toIP[] = state.getSentIP(); + if ( (_transport !=null) && (!_transport.isValid(toIP)) ) { + return null; + } InetAddress to = null; try { - to = InetAddress.getByAddress(state.getSentIP()); + to = InetAddress.getByAddress(toIP); } catch (UnknownHostException uhe) { if (_log.shouldLog(Log.ERROR)) _log.error("How did we think this was a valid IP? " + state.getRemoteHostId().toString()); @@ -321,8 +334,8 @@ public class PacketBuilder { off += state.getSentX().length; DataHelper.toLong(data, off, 1, state.getSentIP().length); off += 1; - System.arraycopy(state.getSentIP(), 0, data, off, state.getSentIP().length); - off += state.getSentIP().length; + System.arraycopy(toIP, 0, data, off, state.getSentIP().length); + off += toIP.length; DataHelper.toLong(data, off, 2, state.getSentPort()); off += 2; diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index 66b856244..c17755784 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -42,7 +42,7 @@ class PeerTestManager { _log = context.logManager().getLog(PeerTestManager.class); _activeTests = new HashMap(64); _recentTests = Collections.synchronizedList(new ArrayList(16)); - _packetBuilder = new PacketBuilder(context); + _packetBuilder = new PacketBuilder(context, transport); _currentTest = null; _context.statManager().createRateStat("udp.statusKnownCharlie", "How often the bob we pick passes us to a charlie we already have a session with?", "udp", new long[] { 60*1000, 20*60*1000, 60*60*1000 }); } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java index d473a5f05..b48138168 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java @@ -742,7 +742,7 @@ public class UDPPacketReader { public static void main(String args[]) { I2PAppContext ctx = I2PAppContext.getGlobalContext(); try { - PacketBuilder b = new PacketBuilder(ctx); + PacketBuilder b = new PacketBuilder(ctx, null); InetAddress introHost = InetAddress.getLocalHost(); int introPort = 1234; byte introKey[] = new byte[SessionKey.KEYSIZE_BYTES]; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index b0718c9f9..05216394a 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -276,9 +276,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * whim. this is not good ;) * */ - void externalAddressReceived(byte ourIP[], int ourPort) { + void externalAddressReceived(Hash from, byte ourIP[], int ourPort) { if (_log.shouldLog(Log.INFO)) - _log.info("External address received: " + RemoteHostId.toString(ourIP) + ":" + ourPort); + _log.info("External address received: " + RemoteHostId.toString(ourIP) + ":" + ourPort + " from " + from.toBase64()); if (explicitAddressSpecified()) return; @@ -286,31 +286,38 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority boolean fixedPort = getIsPortFixed(); boolean updated = false; boolean fireTest = false; - synchronized (this) { - if ( (_externalListenHost == null) || - (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) { - if (!isValid(ourIP)) { - // ignore them - } else if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) || - (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) { - // they told us something different and our tests are either old or failing - try { - _externalListenHost = InetAddress.getByAddress(ourIP); - if (!fixedPort) - _externalListenPort = ourPort; - rebuildExternalAddress(); - replaceAddress(_externalAddress); - updated = true; - } catch (UnknownHostException uhe) { - _externalListenHost = null; + if (!isValid(ourIP)) { + // ignore them + if (_log.shouldLog(Log.ERROR)) + _log.error("The router " + from.toBase64() + " told us we have an invalid IP - " + + RemoteHostId.toString(ourIP) + ". Lets throw tomatoes at them"); + _context.shitlist().shitlistRouter(from, "They said we had an invalid IP"); + return; + } else { + synchronized (this) { + if ( (_externalListenHost == null) || + (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) { + if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) || + (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) { + // they told us something different and our tests are either old or failing + try { + _externalListenHost = InetAddress.getByAddress(ourIP); + if (!fixedPort) + _externalListenPort = ourPort; + rebuildExternalAddress(); + replaceAddress(_externalAddress); + updated = true; + } catch (UnknownHostException uhe) { + _externalListenHost = null; + } + } else { + // they told us something different, but our tests are recent and positive, + // so lets test again + fireTest = true; } } else { - // they told us something different, but our tests are recent and positive, - // so lets test again - fireTest = true; + // matched what we expect } - } else { - // matched what we expect } } @@ -748,7 +755,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _introducersSelectedOn = _context.clock().now(); } } - if ( (_externalListenPort > 0) && (_externalListenHost != null) ) { + if ( (_externalListenPort > 0) && (_externalListenHost != null) && (isValid(_externalListenHost.getAddress())) ) { options.setProperty(UDPAddress.PROP_PORT, String.valueOf(_externalListenPort)); options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress()); // if we have explicit external addresses, they had better be reachable