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();
}
// 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();
}
}

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

View File

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

View File

@ -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);

View File

@ -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 });

View File

@ -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

View File

@ -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; }

View File

@ -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 });

View File

@ -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);

View File

@ -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 });

View File

@ -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;

View File

@ -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 });
}

View File

@ -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];

View File

@ -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