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!)
This commit is contained in:
jrandom
2005-09-30 07:17:56 +00:00
committed by zzz
parent 9f336dd05b
commit 55869af2cc
14 changed files with 122 additions and 61 deletions

View File

@ -73,10 +73,20 @@ public class RouterConsoleRunner {
t.printStackTrace(); 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"); File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed");
if (!noReseedFile.exists()) { File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p");
RouterContext ctx = (RouterContext)RouterContext.listContexts().get(0); File noReseedFileAlt2 = new File(".i2pnoreseed");
if (ctx.netDb().getKnownRouters() < 15) { 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(); ReseedHandler.requestReseed();
} }
} }

View File

@ -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 * 2005-09-29 0.6.1 released

View File

@ -4,7 +4,7 @@
<info> <info>
<appname>i2p</appname> <appname>i2p</appname>
<appversion>0.6.0.6</appversion> <appversion>0.6.1</appversion>
<authors> <authors>
<author name="I2P" email="support@i2p.net"/> <author name="I2P" email="support@i2p.net"/>
</authors> </authors>

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { 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 String VERSION = "0.6.1";
public final static long BUILD = 0; public final static long BUILD = 1;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -29,7 +29,7 @@ public class ACKSender implements Runnable {
_log = ctx.logManager().getLog(ACKSender.class); _log = ctx.logManager().getLog(ACKSender.class);
_transport = transport; _transport = transport;
_peersToACK = new ArrayList(4); _peersToACK = new ArrayList(4);
_builder = new PacketBuilder(_context); _builder = new PacketBuilder(_context, transport);
_alive = true; _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.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 }); _context.statManager().createRateStat("udp.ackFrequency", "how long ago did we send an ACK to this peer?", "udp", new long[] { 60*1000, 60*60*1000 });

View File

@ -52,7 +52,7 @@ public class EstablishmentManager {
_context = ctx; _context = ctx;
_log = ctx.logManager().getLog(EstablishmentManager.class); _log = ctx.logManager().getLog(EstablishmentManager.class);
_transport = transport; _transport = transport;
_builder = new PacketBuilder(ctx); _builder = new PacketBuilder(ctx, transport);
_inboundStates = new HashMap(32); _inboundStates = new HashMap(32);
_outboundStates = new HashMap(32); _outboundStates = new HashMap(32);
_queuedOutbound = new HashMap(32); _queuedOutbound = new HashMap(32);
@ -130,6 +130,7 @@ public class EstablishmentManager {
if (!_transport.isValid(to.getIP())) { if (!_transport.isValid(to.getIP())) {
_transport.failed(msg); _transport.failed(msg);
_context.shitlist().shitlistRouter(msg.getTarget().getIdentity().calculateHash(), "Invalid SSU address");
return; return;
} }
@ -529,8 +530,13 @@ public class EstablishmentManager {
if (!valid) // validate clears fields on failure if (!valid) // validate clears fields on failure
return; return;
if (!_transport.isValid(state.getReceivedIP()) || !_transport.isValid(state.getRemoteHostId().getIP())) {
state.fail();
return;
}
// gives us the opportunity to "detect" our external addr // 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 // signs if we havent signed yet
state.prepareSessionConfirmed(); state.prepareSessionConfirmed();
@ -573,6 +579,9 @@ public class EstablishmentManager {
_context.statManager().addRateData("udp.inboundEstablishFailedState", cur.getState(), cur.getLifetime()); _context.statManager().addRateData("udp.inboundEstablishFailedState", cur.getState(), cur.getLifetime());
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Removing expired inbound state"); _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 { } else {
if (cur.getNextSendTime() <= now) { if (cur.getNextSendTime() <= now) {
// our turn... // our turn...
@ -619,6 +628,8 @@ public class EstablishmentManager {
_log.warn("why are we confirmed with no identity? " + inboundState); _log.warn("why are we confirmed with no identity? " + inboundState);
break; break;
} }
case InboundEstablishState.STATE_FAILED:
break; // already removed;
case InboundEstablishState.STATE_UNKNOWN: // fallthrough case InboundEstablishState.STATE_UNKNOWN: // fallthrough
default: default:
// wtf // wtf

View File

@ -65,6 +65,8 @@ public class InboundEstablishState {
public static final int STATE_CONFIRMED_PARTIALLY = 3; public static final int STATE_CONFIRMED_PARTIALLY = 3;
/** we have completely received all of the confirmation packets */ /** we have completely received all of the confirmation packets */
public static final int STATE_CONFIRMED_COMPLETELY = 4; 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) { public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort) {
_context = ctx; _context = ctx;
@ -128,6 +130,10 @@ public class InboundEstablishState {
return _sentY; return _sentY;
} }
public synchronized void fail() {
_currentState = STATE_FAILED;
}
public synchronized long getSentRelayTag() { return _sentRelayTag; } public synchronized long getSentRelayTag() { return _sentRelayTag; }
public synchronized void setSentRelayTag(long tag) { _sentRelayTag = tag; } public synchronized void setSentRelayTag(long tag) { _sentRelayTag = tag; }
public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; } public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; }

View File

@ -23,7 +23,7 @@ public class IntroductionManager {
_context = ctx; _context = ctx;
_log = ctx.logManager().getLog(IntroductionManager.class); _log = ctx.logManager().getLog(IntroductionManager.class);
_transport = transport; _transport = transport;
_builder = new PacketBuilder(ctx); _builder = new PacketBuilder(ctx, transport);
_outbound = Collections.synchronizedMap(new HashMap(128)); _outbound = Collections.synchronizedMap(new HashMap(128));
_inbound = new ArrayList(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 }); 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 });

View File

@ -198,24 +198,28 @@ public class OutboundEstablishState {
} else { } else {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Session created failed validation, clearing state for " + _remoteHostId.toString()); _log.warn("Session created failed validation, clearing state for " + _remoteHostId.toString());
_receivedY = null; fail();
_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();
return false; 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 { private void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException {
if (_sessionKey != null) return; if (_sessionKey != null) return;
_keyBuilder.setPeerPublicValue(_receivedY); _keyBuilder.setPeerPublicValue(_receivedY);

View File

@ -48,7 +48,7 @@ public class OutboundMessageFragments {
_throttle = throttle; _throttle = throttle;
_activeMessages = new ArrayList(MAX_ACTIVE); _activeMessages = new ArrayList(MAX_ACTIVE);
_nextPacketMessage = 0; _nextPacketMessage = 0;
_builder = new PacketBuilder(ctx); _builder = new PacketBuilder(ctx, transport);
_alive = true; _alive = true;
_allowExcess = false; _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 }); _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 });

View File

@ -25,13 +25,15 @@ import net.i2p.util.Log;
public class PacketBuilder { public class PacketBuilder {
private I2PAppContext _context; private I2PAppContext _context;
private Log _log; private Log _log;
private UDPTransport _transport;
private static final ByteCache _ivCache = ByteCache.getInstance(64, UDPPacket.IV_SIZE); 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 _hmacCache = ByteCache.getInstance(64, Hash.HASH_LENGTH);
private static final ByteCache _blockCache = ByteCache.getInstance(64, 16); private static final ByteCache _blockCache = ByteCache.getInstance(64, 16);
public PacketBuilder(I2PAppContext ctx) { public PacketBuilder(I2PAppContext ctx, UDPTransport transport) {
_context = ctx; _context = ctx;
_transport = transport;
_log = ctx.logManager().getLog(PacketBuilder.class); _log = ctx.logManager().getLog(PacketBuilder.class);
} }
@ -224,13 +226,20 @@ public class PacketBuilder {
DataHelper.toLong(data, off, 4, now); DataHelper.toLong(data, off, 4, now);
off += 4; 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 // now for the body
System.arraycopy(state.getSentY(), 0, data, off, state.getSentY().length); System.arraycopy(state.getSentY(), 0, data, off, state.getSentY().length);
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; off += 1;
System.arraycopy(state.getSentIP(), 0, data, off, state.getSentIP().length); System.arraycopy(sentIP, 0, data, off, sentIP.length);
off += state.getSentIP().length; off += sentIP.length;
DataHelper.toLong(data, off, 2, state.getSentPort()); DataHelper.toLong(data, off, 2, state.getSentPort());
off += 2; off += 2;
DataHelper.toLong(data, off, 4, state.getSentRelayTag()); DataHelper.toLong(data, off, 4, state.getSentRelayTag());
@ -249,7 +258,7 @@ public class PacketBuilder {
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append("Sending sessionCreated:"); 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(" AlicePort: ").append(state.getSentPort());
buf.append(" BobIP: ").append(Base64.encode(state.getReceivedOurIP())); buf.append(" BobIP: ").append(Base64.encode(state.getReceivedOurIP()));
buf.append(" BobPort: ").append(externalPort); buf.append(" BobPort: ").append(externalPort);
@ -294,9 +303,13 @@ public class PacketBuilder {
*/ */
public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) {
UDPPacket packet = UDPPacket.acquire(_context); UDPPacket packet = UDPPacket.acquire(_context);
byte toIP[] = state.getSentIP();
if ( (_transport !=null) && (!_transport.isValid(toIP)) ) {
return null;
}
InetAddress to = null; InetAddress to = null;
try { try {
to = InetAddress.getByAddress(state.getSentIP()); to = InetAddress.getByAddress(toIP);
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("How did we think this was a valid IP? " + state.getRemoteHostId().toString()); _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; off += state.getSentX().length;
DataHelper.toLong(data, off, 1, state.getSentIP().length); DataHelper.toLong(data, off, 1, state.getSentIP().length);
off += 1; off += 1;
System.arraycopy(state.getSentIP(), 0, data, off, state.getSentIP().length); System.arraycopy(toIP, 0, data, off, state.getSentIP().length);
off += state.getSentIP().length; off += toIP.length;
DataHelper.toLong(data, off, 2, state.getSentPort()); DataHelper.toLong(data, off, 2, state.getSentPort());
off += 2; off += 2;

View File

@ -42,7 +42,7 @@ class PeerTestManager {
_log = context.logManager().getLog(PeerTestManager.class); _log = context.logManager().getLog(PeerTestManager.class);
_activeTests = new HashMap(64); _activeTests = new HashMap(64);
_recentTests = Collections.synchronizedList(new ArrayList(16)); _recentTests = Collections.synchronizedList(new ArrayList(16));
_packetBuilder = new PacketBuilder(context); _packetBuilder = new PacketBuilder(context, transport);
_currentTest = null; _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 }); _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 });
} }

View File

@ -742,7 +742,7 @@ public class UDPPacketReader {
public static void main(String args[]) { public static void main(String args[]) {
I2PAppContext ctx = I2PAppContext.getGlobalContext(); I2PAppContext ctx = I2PAppContext.getGlobalContext();
try { try {
PacketBuilder b = new PacketBuilder(ctx); PacketBuilder b = new PacketBuilder(ctx, null);
InetAddress introHost = InetAddress.getLocalHost(); InetAddress introHost = InetAddress.getLocalHost();
int introPort = 1234; int introPort = 1234;
byte introKey[] = new byte[SessionKey.KEYSIZE_BYTES]; byte introKey[] = new byte[SessionKey.KEYSIZE_BYTES];

View File

@ -276,9 +276,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
* whim. this is not good ;) * whim. this is not good ;)
* *
*/ */
void externalAddressReceived(byte ourIP[], int ourPort) { void externalAddressReceived(Hash from, byte ourIP[], int ourPort) {
if (_log.shouldLog(Log.INFO)) 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()) if (explicitAddressSpecified())
return; return;
@ -286,31 +286,38 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
boolean fixedPort = getIsPortFixed(); boolean fixedPort = getIsPortFixed();
boolean updated = false; boolean updated = false;
boolean fireTest = false; boolean fireTest = false;
synchronized (this) { if (!isValid(ourIP)) {
if ( (_externalListenHost == null) || // ignore them
(!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) { if (_log.shouldLog(Log.ERROR))
if (!isValid(ourIP)) { _log.error("The router " + from.toBase64() + " told us we have an invalid IP - "
// ignore them + RemoteHostId.toString(ourIP) + ". Lets throw tomatoes at them");
} else if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) || _context.shitlist().shitlistRouter(from, "They said we had an invalid IP");
(_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) { return;
// they told us something different and our tests are either old or failing } else {
try { synchronized (this) {
_externalListenHost = InetAddress.getByAddress(ourIP); if ( (_externalListenHost == null) ||
if (!fixedPort) (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) {
_externalListenPort = ourPort; if ( (_reachabilityStatus == CommSystemFacade.STATUS_UNKNOWN) ||
rebuildExternalAddress(); (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) {
replaceAddress(_externalAddress); // they told us something different and our tests are either old or failing
updated = true; try {
} catch (UnknownHostException uhe) { _externalListenHost = InetAddress.getByAddress(ourIP);
_externalListenHost = null; 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 { } else {
// they told us something different, but our tests are recent and positive, // matched what we expect
// so lets test again
fireTest = true;
} }
} else {
// matched what we expect
} }
} }
@ -748,7 +755,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_introducersSelectedOn = _context.clock().now(); _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_PORT, String.valueOf(_externalListenPort));
options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress()); options.setProperty(UDPAddress.PROP_HOST, _externalListenHost.getHostAddress());
// if we have explicit external addresses, they had better be reachable // if we have explicit external addresses, they had better be reachable