diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index a51dead90..7c4e787fd 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -424,9 +424,9 @@
- <%=intl._("Save")%>(S )
- accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><%=intl._("Delete")%>(D )
<%=intl._("Cancel")%>
+ accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><%=intl._("Delete")%>(D )
+ <%=intl._("Save")%>(S )
diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp
index 90a7614f2..0f970eb7e 100644
--- a/apps/i2ptunnel/jsp/editServer.jsp
+++ b/apps/i2ptunnel/jsp/editServer.jsp
@@ -341,7 +341,7 @@
- <%=intl._("Restricted Access List")%>(s ): <%=intl._("Unimplemented")%>
+ <%=intl._("Restricted Access List")%>(s ):
@@ -457,9 +457,9 @@
-
<%=intl._("Save")%>(S )
-
accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><%=intl._("Delete")%>(D )
<%=intl._("Cancel")%>
+
accesskey="D" class="control" type="submit" name="action" value="Delete this proxy" title="Delete this Proxy"><%=intl._("Delete")%>(D )
+
<%=intl._("Save")%>(S )
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java
index f69a0059c..49cc0476a 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java
@@ -135,6 +135,14 @@ public class ConnectionManager {
// active++;
//}
if (locked_tooManyStreams()) {
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Refusing connection since we have exceeded our max of "
+ + _maxConcurrentStreams + " connections");
+ reject = true;
+ } else if (shouldRejectConnection(synPacket)) {
+ _log.error("Refusing connection since peer is " +
+ (_defaultOptions.isAccessListEnabled() ? "not whitelisted: " : "blacklisted: ") +
+ (synPacket.getOptionalFrom() == null ? "null from" : synPacket.getOptionalFrom().calculateHash().toBase64()));
reject = true;
} else {
while (true) {
@@ -151,9 +159,6 @@ public class ConnectionManager {
_context.statManager().addRateData("stream.receiveActive", active, total);
if (reject) {
- if (_log.shouldLog(Log.WARN))
- _log.warn("Refusing connection since we have exceeded our max of "
- + _maxConcurrentStreams + " connections");
PacketLocal reply = new PacketLocal(_context, synPacket.getOptionalFrom());
reply.setFlag(Packet.FLAG_RESET);
reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
@@ -270,6 +275,21 @@ public class ConnectionManager {
return (active >= _maxConcurrentStreams);
}
+ private boolean shouldRejectConnection(Packet syn) {
+ // unfortunately we don't have access to the router client manager here,
+ // so we can't whitelist local access
+ Destination from = syn.getOptionalFrom();
+ if (from == null)
+ return true;
+ // if the sig is absent or bad it will be caught later (in CPH)
+ if (_defaultOptions.isAccessListEnabled())
+ return !_defaultOptions.getAccessList().contains(from.calculateHash());
+ if (_defaultOptions.isBlacklistEnabled())
+ return _defaultOptions.getBlacklist().contains(from.calculateHash());
+ return false;
+ }
+
+
public MessageHandler getMessageHandler() { return _messageHandler; }
public PacketHandler getPacketHandler() { return _packetHandler; }
public I2PSession getSession() { return _session; }
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java
index ea4e1f069..da3bd48f8 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java
@@ -1,6 +1,15 @@
package net.i2p.client.streaming;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import net.i2p.I2PAppContext;
+import net.i2p.data.Hash;
+import net.i2p.util.ConvertToHash;
+import net.i2p.util.Log;
/**
* Define the current options for the con (and allow custom tweaking midstream)
@@ -27,6 +36,10 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
private int _maxWindowSize;
private int _congestionAvoidanceGrowthRateFactor;
private int _slowStartGrowthRateFactor;
+ private boolean _accessListEnabled;
+ private boolean _blackListEnabled;
+ private Set _accessList;
+ private Set _blackList;
public static final int PROFILE_BULK = 1;
public static final int PROFILE_INTERACTIVE = 2;
@@ -54,6 +67,9 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
public static final String PROP_CONGESTION_AVOIDANCE_GROWTH_RATE_FACTOR = "i2p.streaming.congestionAvoidanceGrowthRateFactor";
public static final String PROP_SLOW_START_GROWTH_RATE_FACTOR = "i2p.streaming.slowStartGrowthRateFactor";
public static final String PROP_ANSWER_PINGS = "i2p.streaming.answerPings";
+ public static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
+ public static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
+ public static final String PROP_ACCESS_LIST = "i2cp.accessList";
private static final int TREND_COUNT = 3;
static final int INITIAL_WINDOW_SIZE = 6;
@@ -205,6 +221,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
setWriteTimeout(opts.getWriteTimeout());
setReadTimeout(opts.getReadTimeout());
setAnswerPings(opts.getAnswerPings());
+ initLists(opts);
}
}
@@ -230,6 +247,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
setSlowStartGrowthRateFactor(getInt(opts, PROP_SLOW_START_GROWTH_RATE_FACTOR, 1));
setConnectTimeout(getInt(opts, PROP_CONNECT_TIMEOUT, Connection.DISCONNECT_TIMEOUT));
setAnswerPings(getBool(opts, PROP_ANSWER_PINGS, DEFAULT_ANSWER_PINGS));
+ initLists(opts);
}
@Override
@@ -272,6 +290,7 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
setConnectTimeout(getInt(opts, PROP_CONNECT_TIMEOUT, Connection.DISCONNECT_TIMEOUT));
if (opts.containsKey(PROP_ANSWER_PINGS))
setAnswerPings(getBool(opts, PROP_ANSWER_PINGS, DEFAULT_ANSWER_PINGS));
+ initLists(opts);
}
/**
@@ -504,6 +523,57 @@ public class ConnectionOptions extends I2PSocketOptionsImpl {
public int getSlowStartGrowthRateFactor() { return _slowStartGrowthRateFactor; }
public void setSlowStartGrowthRateFactor(int factor) { _slowStartGrowthRateFactor = factor; }
+ public boolean isAccessListEnabled() { return _accessListEnabled; }
+ public boolean isBlacklistEnabled() { return _blackListEnabled; }
+ public Set getAccessList() { return _accessList; }
+ public Set getBlacklist() { return _blackList; }
+
+ private void initLists(ConnectionOptions opts) {
+ _accessListEnabled = opts.isAccessListEnabled();
+ _blackListEnabled = opts.isBlacklistEnabled();
+ _accessList = opts.getAccessList();
+ _blackList = opts.getBlacklist();
+ }
+
+ private void initLists(Properties opts) {
+ _accessListEnabled = getBool(opts, PROP_ENABLE_ACCESS_LIST, false);
+ _blackListEnabled = getBool(opts, PROP_ENABLE_BLACKLIST, false);
+ if (_accessListEnabled)
+ _accessList = new HashSet();
+ else
+ _accessList = Collections.EMPTY_SET;
+ if (_blackListEnabled)
+ _blackList = new HashSet();
+ else
+ _blackList = Collections.EMPTY_SET;
+ if (!(_accessListEnabled || _blackListEnabled))
+ return;
+ String hashes = opts.getProperty(PROP_ACCESS_LIST);
+ if (hashes == null)
+ return;
+ StringTokenizer tok = new StringTokenizer(hashes, ", ");
+ while (tok.hasMoreTokens()) {
+ String hashstr = tok.nextToken();
+ Hash h = ConvertToHash.getHash(hashstr);
+ if (h == null)
+ error("bad list hash: " + hashstr);
+ else if (_blackListEnabled)
+ _blackList.add(h);
+ else
+ _accessList.add(h);
+ }
+ if (_accessListEnabled && _accessList.isEmpty())
+ error("Connection access list enabled but no valid entries; no peers can connect");
+ else if (_blackListEnabled && _blackList.isEmpty())
+ error("Connection blacklist enabled but no valid entries; all peers can connect");
+ }
+
+ private static void error(String s) {
+ I2PAppContext ctx = I2PAppContext.getGlobalContext();
+ Log log = ctx.logManager().getLog(ConnectionOptions.class);
+ log.error(s);
+ }
+
@Override
public String toString() {
StringBuilder buf = new StringBuilder(128);
diff --git a/history.txt b/history.txt
index 0b07ff332..ac6f60dd6 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,14 @@
+2010-04-12 zzz
+ * configstats.jsp: Fix full stats checkbox default
+ * i2psnark:
+ - Concurrent, limit, display, log tweaks
+ * i2ptunnel: Implement access lists for TCP servers.
+ Enter b32 or b64 hash or dest into list box, and
+ check enable for whitelist. Uncheck enable and enter
+ i2cp.enableBlackList=true in advanced i2cp options for
+ blacklist. Todo: make black/whitelists radio buttons.
+ * LogManager: Concurrent
+
2010-04-10 zzz
* i2psnark:
- Disconnect seeds that connect to a seed
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index a6204817e..f2522cd4e 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 = 8;
+ public final static long BUILD = 9;
/** for example "-test" */
public final static String EXTRA = "";