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