diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 6c7ed7dd1..e84c4a5c3 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -48,8 +48,8 @@ import net.i2p.util.ReusableGZIPOutputStream; * @author jrandom */ public class DataHelper { - private final static byte _equalBytes[] = "=".getBytes(); // in UTF-8 - private final static byte _semicolonBytes[] = ";".getBytes(); // in UTF-8 + private final static byte EQUAL_BYTES[] = "=".getBytes(); // in UTF-8 + private final static byte SEMICOLON_BYTES[] = ";".getBytes(); // in UTF-8 /** Read a mapping from the stream, as defined by the I2P data structure spec, * and store it into a Properties object. @@ -76,17 +76,17 @@ public class DataHelper { int read = read(rawStream, data); if (read != size) throw new DataFormatException("Not enough data to read the properties"); ByteArrayInputStream in = new ByteArrayInputStream(data); - byte eqBuf[] = new byte[_equalBytes.length]; - byte semiBuf[] = new byte[_semicolonBytes.length]; + byte eqBuf[] = new byte[EQUAL_BYTES.length]; + byte semiBuf[] = new byte[SEMICOLON_BYTES.length]; while (in.available() > 0) { String key = readString(in); read = read(in, eqBuf); - if ((read != eqBuf.length) || (!eq(eqBuf, _equalBytes))) { + if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) { break; } String val = readString(in); read = read(in, semiBuf); - if ((read != semiBuf.length) || (!eq(semiBuf, _semicolonBytes))) { + if ((read != semiBuf.length) || (!eq(semiBuf, SEMICOLON_BYTES))) { break; } props.put(key, val); @@ -123,7 +123,7 @@ public class DataHelper { if (props != null) { OrderedProperties p = new OrderedProperties(); p.putAll(props); - ByteArrayOutputStream baos = new ByteArrayOutputStream(32); + ByteArrayOutputStream baos = new ByteArrayOutputStream(p.size() * 64); for (Iterator iter = p.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); String val = p.getProperty(key); @@ -131,15 +131,17 @@ public class DataHelper { writeStringUTF8(baos, key); else writeString(baos, key); - baos.write(_equalBytes); + baos.write(EQUAL_BYTES); if (utf8) writeStringUTF8(baos, val); else writeString(baos, val); - baos.write(_semicolonBytes); + baos.write(SEMICOLON_BYTES); } baos.close(); byte propBytes[] = baos.toByteArray(); + if (propBytes.length > 65535) + throw new DataFormatException("Properties too big (65535 max): " + propBytes.length); writeLong(rawStream, 2, propBytes.length); rawStream.write(propBytes); } else { @@ -164,9 +166,9 @@ public class DataHelper { //key = new String(key.getBytes(), "UTF-8"); //val = new String(val.getBytes(), "UTF-8"); writeString(baos, key); - baos.write(_equalBytes); + baos.write(EQUAL_BYTES); writeString(baos, val); - baos.write(_semicolonBytes); + baos.write(SEMICOLON_BYTES); } baos.close(); byte propBytes[] = baos.toByteArray(); @@ -190,17 +192,17 @@ public class DataHelper { int size = (int)fromLong(source, offset, 2); offset += 2; ByteArrayInputStream in = new ByteArrayInputStream(source, offset, size); - byte eqBuf[] = new byte[_equalBytes.length]; - byte semiBuf[] = new byte[_semicolonBytes.length]; + byte eqBuf[] = new byte[EQUAL_BYTES.length]; + byte semiBuf[] = new byte[SEMICOLON_BYTES.length]; while (in.available() > 0) { String key = readString(in); int read = read(in, eqBuf); - if ((read != eqBuf.length) || (!eq(eqBuf, _equalBytes))) { + if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) { break; } String val = readString(in); read = read(in, semiBuf); - if ((read != semiBuf.length) || (!eq(semiBuf, _semicolonBytes))) { + if ((read != semiBuf.length) || (!eq(semiBuf, SEMICOLON_BYTES))) { break; } target.put(key, val); diff --git a/history.txt b/history.txt index f505b5da0..d64ca92d5 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,14 @@ +2010-01-28 zzz + * Clock: Don't refuse to update because of peer skew the first time + * I2NP: Various cleanup and bulletproofing + * Log: Try to avoid complaints at shutdown + * Profiles: Fix lack of profiles at router startup, especially for new routers + * stats.jsp: Shrink the dropdown box + +2010-01-26 zzz + * build.xml: Speed up distclean additions + * Debian: Fixup, update, enhance scripts + 2010-01-24 zzz * ProfileOrganizerRenderer: Cleanups * Reseed: Update welt's reseed hostname diff --git a/router/java/src/net/i2p/data/i2np/DataMessage.java b/router/java/src/net/i2p/data/i2np/DataMessage.java index 641d6b40b..e98630bc8 100644 --- a/router/java/src/net/i2p/data/i2np/DataMessage.java +++ b/router/java/src/net/i2p/data/i2np/DataMessage.java @@ -22,8 +22,6 @@ public class DataMessage extends I2NPMessageImpl { public final static int MESSAGE_TYPE = 20; private byte _data[]; - // private static final int MAX_SIZE = 64*1024; // LINT -- field hides another field, and not used - public DataMessage(I2PAppContext context) { super(context); _data = null; @@ -48,7 +46,7 @@ public class DataMessage extends I2NPMessageImpl { int curIndex = offset; long size = DataHelper.fromLong(data, curIndex, 4); curIndex += 4; - if (size > 64*1024) + if (size > MAX_SIZE) throw new I2NPMessageException("wtf, size=" + size); _data = new byte[(int)size]; System.arraycopy(data, curIndex, _data, 0, (int)size); diff --git a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java index 43e2ee8d5..3b197ee92 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java @@ -17,7 +17,7 @@ import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.TunnelId; -import net.i2p.util.Log; +//import net.i2p.util.Log; /** * Defines the message a router sends to another router to search for a @@ -26,18 +26,22 @@ import net.i2p.util.Log; * @author jrandom */ public class DatabaseLookupMessage extends I2NPMessageImpl { - private final static Log _log = new Log(DatabaseLookupMessage.class); + //private final static Log _log = new Log(DatabaseLookupMessage.class); public final static int MESSAGE_TYPE = 2; private Hash _key; private Hash _fromHash; private TunnelId _replyTunnel; - private Set _dontIncludePeers; + private Set _dontIncludePeers; - private static volatile long _currentLookupPeriod = 0; - private static volatile int _currentLookupCount = 0; + //private static volatile long _currentLookupPeriod = 0; + //private static volatile int _currentLookupCount = 0; // if we try to send over 20 netDb lookups in 10 seconds, we're acting up - private static final long LOOKUP_THROTTLE_PERIOD = 10*1000; - private static final long LOOKUP_THROTTLE_MAX = 50; + //private static final long LOOKUP_THROTTLE_PERIOD = 10*1000; + //private static final long LOOKUP_THROTTLE_MAX = 50; + + /** Insanely big. Not much more than 1500 will fit in a message. + Have to prevent a huge alloc on rcv of a malicious msg though */ + private static final int MAX_NUM_PEERS = 512; public DatabaseLookupMessage(I2PAppContext context) { this(context, false); @@ -48,24 +52,27 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { //setFrom(null); //setDontIncludePeers(null); - context.statManager().createRateStat("router.throttleNetDbDoSSend", "How many netDb lookup messages we are sending during a period with a DoS detected", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); - + // This is the wrong place for this, any throttling should be in netdb + // And it doesnt throttle anyway (that would have to be in netdb), it just increments a stat + //context.statManager().createRateStat("router.throttleNetDbDoSSend", "How many netDb lookup messages we are sending during a period with a DoS detected", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 }); + // // only check DoS generation if we are creating the message... - if (locallyCreated) { - // we do this in the writeMessage so we know that we have all the data - int dosCount = detectDoS(context); - if (dosCount > 0) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Are we flooding the network with NetDb messages? (" + dosCount - + " messages so far)", new Exception("Flood cause")); - } - } + //if (locallyCreated) { + // // we do this in the writeMessage so we know that we have all the data + // int dosCount = detectDoS(context); + // if (dosCount > 0) { + // if (_log.shouldLog(Log.WARN)) + // _log.warn("Are we flooding the network with NetDb messages? (" + dosCount + // + " messages so far)", new Exception("Flood cause")); + // } + //} } /** * Return number of netDb messages in this period, if flood, else 0 * */ +/***** private static int detectDoS(I2PAppContext context) { int count = _currentLookupCount++; // now lets check for DoS @@ -87,6 +94,7 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { return 0; } } +*****/ /** * Defines the key being searched for @@ -113,7 +121,7 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { * * @return Set of Hash objects, each of which is the H(routerIdentity) to skip */ - public Set getDontIncludePeers() { return _dontIncludePeers; } + public Set getDontIncludePeers() { return _dontIncludePeers; } public void setDontIncludePeers(Set peers) { if (peers != null) _dontIncludePeers = new HashSet(peers); @@ -156,9 +164,9 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { int numPeers = (int)DataHelper.fromLong(data, curIndex, 2); curIndex += 2; - if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) + if ( (numPeers < 0) || (numPeers > MAX_NUM_PEERS) ) throw new I2NPMessageException("Invalid number of peers - " + numPeers); - Set peers = new HashSet(numPeers); + Set peers = new HashSet(numPeers); for (int i = 0; i < numPeers; i++) { byte peer[] = new byte[Hash.HASH_LENGTH]; System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); @@ -201,11 +209,14 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { out[curIndex++] = 0x0; out[curIndex++] = 0x0; } else { - byte len[] = DataHelper.toLong(2, _dontIncludePeers.size()); + int size = _dontIncludePeers.size(); + if (size > MAX_NUM_PEERS) + throw new I2NPMessageException("Too many peers: " + size); + byte len[] = DataHelper.toLong(2, size); out[curIndex++] = len[0]; out[curIndex++] = len[1]; - for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) { - Hash peer = (Hash)iter.next(); + for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) { + Hash peer = iter.next(); System.arraycopy(peer.getData(), 0, out, curIndex, Hash.HASH_LENGTH); curIndex += Hash.HASH_LENGTH; } diff --git a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java index ab3a7f678..085edc5a0 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java @@ -26,13 +26,14 @@ import net.i2p.data.Hash; public class DatabaseSearchReplyMessage extends I2NPMessageImpl { public final static int MESSAGE_TYPE = 3; private Hash _key; - private List _peerHashes; + private List _peerHashes; private Hash _from; public DatabaseSearchReplyMessage(I2PAppContext context) { super(context); - _context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); - _context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); + // do this in netdb if we need it + //_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); + //_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); setSearchKey(null); _peerHashes = new ArrayList(3); setFromHash(null); @@ -45,7 +46,7 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { public void setSearchKey(Hash key) { _key = key; } public int getNumReplies() { return _peerHashes.size(); } - public Hash getReply(int index) { return (Hash)_peerHashes.get(index); } + public Hash getReply(int index) { return _peerHashes.get(index); } public void addReply(Hash peer) { _peerHashes.add(peer); } //public void addReplies(Collection replies) { _peerHashes.addAll(replies); } @@ -77,7 +78,7 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { curIndex += Hash.HASH_LENGTH; _from = new Hash(from); - _context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1); + //_context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1); } /** calculate the message body's length (not including the header and footer */ diff --git a/router/java/src/net/i2p/data/i2np/GarlicMessage.java b/router/java/src/net/i2p/data/i2np/GarlicMessage.java index 88d2f2b37..72d7e5d06 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicMessage.java +++ b/router/java/src/net/i2p/data/i2np/GarlicMessage.java @@ -44,7 +44,7 @@ public class GarlicMessage extends I2NPMessageImpl { long len = DataHelper.fromLong(data, curIndex, 4); curIndex += 4; - if ( (len <= 0) || (len > 64*1024) ) throw new I2NPMessageException("size="+len); + if ( (len <= 0) || (len > MAX_SIZE) ) throw new I2NPMessageException("size="+len); _data = new byte[(int)len]; System.arraycopy(data, curIndex, _data, 0, (int)len); } diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index f89c6cbfe..e841160d6 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -373,8 +373,9 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM return new DatabaseSearchReplyMessage(context); case DeliveryStatusMessage.MESSAGE_TYPE: return new DeliveryStatusMessage(context); - case DateMessage.MESSAGE_TYPE: - return new DateMessage(context); + // unused since forever (0.5?) + //case DateMessage.MESSAGE_TYPE: + // return new DateMessage(context); case GarlicMessage.MESSAGE_TYPE: return new GarlicMessage(context); case TunnelDataMessage.MESSAGE_TYPE: @@ -383,6 +384,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM return new TunnelGatewayMessage(context); case DataMessage.MESSAGE_TYPE: return new DataMessage(context); + // unused since 0.6.1.10 //case TunnelCreateMessage.MESSAGE_TYPE: // return new TunnelCreateMessage(context); //case TunnelCreateStatusMessage.MESSAGE_TYPE: diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f17951822..fb40e5644 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 2; + public final static long BUILD = 3; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/data/i2np/DateMessage.java b/router/java/test/net/i2p/data/i2np/DateMessage.java similarity index 100% rename from router/java/src/net/i2p/data/i2np/DateMessage.java rename to router/java/test/net/i2p/data/i2np/DateMessage.java