diff --git a/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java b/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java
index 47f0d1f78c..c6f878418e 100644
--- a/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java
+++ b/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java
@@ -249,8 +249,10 @@ public class Analysis {
return avg;
}
- private double closestDistance(Hash h, List ris) {
- BigInteger min = (new BigInteger("2")).pow(256);
+ private static final BigInteger BI_MAX = (new BigInteger("2")).pow(256);
+
+ private static double closestDistance(Hash h, List ris) {
+ BigInteger min = BI_MAX;
for (RouterInfo info : ris) {
BigInteger dist = HashDistance.getDistance(h, info.getHash());
if (dist.compareTo(min) < 0)
diff --git a/apps/routerconsole/java/src/net/i2p/router/sybil/PersistSybil.java b/apps/routerconsole/java/src/net/i2p/router/sybil/PersistSybil.java
index cc9523d928..7efa5a5cde 100644
--- a/apps/routerconsole/java/src/net/i2p/router/sybil/PersistSybil.java
+++ b/apps/routerconsole/java/src/net/i2p/router/sybil/PersistSybil.java
@@ -95,7 +95,7 @@ public class PersistSybil {
rv.add(Long.valueOf(d));
} catch (NumberFormatException nfe) {}
}
- Collections.sort(rv);
+ Collections.sort(rv, Collections.reverseOrder());
return rv;
}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/NetDbHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/NetDbHelper.java
index 15b3b86603..d90d04fcaf 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/NetDbHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/NetDbHelper.java
@@ -13,7 +13,8 @@ public class NetDbHelper extends HelperBase {
private String _version;
private String _country;
private String _family, _caps, _ip, _sybil, _mtu, _ssucaps, _ipv6, _transport;
- private int _full, _port, _cost, _page;
+ private int _full, _port, _cost, _page, _mode;
+ private long _date;
private int _limit = DEFAULT_LIMIT;
private boolean _lease;
private boolean _debug;
@@ -141,6 +142,20 @@ public class NetDbHelper extends HelperBase {
} catch (NumberFormatException nfe) {}
}
+ /** @since 0.9.38 */
+ public void setMode(String f) {
+ try {
+ _mode = Integer.parseInt(f);
+ } catch (NumberFormatException nfe) {}
+ }
+
+ /** @since 0.9.38 */
+ public void setDate(String f) {
+ try {
+ _date = Long.parseLong(f);
+ } catch (NumberFormatException nfe) {}
+ }
+
public void setFull(String f) {
try {
_full = Integer.parseInt(f);
@@ -198,7 +213,7 @@ public class NetDbHelper extends HelperBase {
else if (_lease)
renderer.renderLeaseSetHTML(_out, _debug);
else if (_full == 3)
- (new SybilRenderer(_context)).getNetDbSummary(_out);
+ (new SybilRenderer(_context)).getNetDbSummary(_out, _mode, _date);
else if (_full == 4)
renderLookupForm();
else
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SybilRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SybilRenderer.java
index 950902c3cf..4b18a85418 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SybilRenderer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SybilRenderer.java
@@ -12,6 +12,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -32,6 +33,7 @@ import net.i2p.router.peermanager.DBHistory;
import net.i2p.router.peermanager.PeerProfile;
import net.i2p.router.sybil.Analysis;
import net.i2p.router.sybil.Pair;
+import net.i2p.router.sybil.PersistSybil;
import net.i2p.router.sybil.Points;
import static net.i2p.router.sybil.Util.biLog2;
import net.i2p.router.tunnel.pool.TunnelPool;
@@ -70,9 +72,12 @@ public class SybilRenderer {
/**
* Entry point
+ *
+ * @param mode what tab to show
+ * @param date only for mode = 12
*/
- public String getNetDbSummary(Writer out) throws IOException {
- renderRouterInfoHTML(out, (String)null);
+ public String getNetDbSummary(Writer out, int mode, long date) throws IOException {
+ renderRouterInfoHTML(out, mode, date);
return "";
}
@@ -115,11 +120,11 @@ public class SybilRenderer {
/**
* The whole thing
*
- * @param routerPrefix ignored
+ * @param mode what tab to show
+ * @param date only for mode = 12
*/
- private void renderRouterInfoHTML(Writer out, String routerPrefix) throws IOException {
+ private void renderRouterInfoHTML(Writer out, int mode, long date) throws IOException {
Hash us = _context.routerHash();
- Hash ourRKey = _context.router().getRouterInfo().getRoutingKey();
Analysis analysis = new Analysis(_context);
List ris = analysis.getFloodfills(us);
if (ris.isEmpty()) {
@@ -131,24 +136,117 @@ public class SybilRenderer {
buf.append("This is an experimental network database tool for debugging and analysis. Do not panic even if you see warnings below. " +
"Possible \"threats\" are summarized at the bottom, however these are unlikely to be real threats. " +
"If you see anything you would like to discuss with the devs, contact us on IRC #i2p-dev.
" +
- "- FF Summary" +
- "
- Same Family" +
- "
- IP close to us" +
- "
- Same IP" +
- "
- Same /24" +
- "
- Same /16" +
- "
- Pair distance" +
- "
- Close to us" +
- "
- Close to us tomorrow" +
- "
- DHT neighbors" +
- "
- Close to our destinations" +
- "
- Highest threats" +
+ "");
-
- renderRouterInfo(buf, _context.router().getRouterInfo(), null, true, false);
- buf.append("
Known Floodfills: ").append(ris.size()).append("
");
+ writeBuf(out, buf);
double avgMinDist = analysis.getAvgMinDist(ris);
+ Map points = new HashMap(64);
+
+ if (mode == 0) {
+ renderOverview(out, buf, analysis);
+ } else if (mode == 1) {
+ renderFFSummary(out, buf, ris, avgMinDist);
+ } else if (mode == 2) {
+ renderFamilySummary(out, buf, analysis, ris, points);
+ } else if (mode == 3) {
+ renderIPUsSummary(out, buf, analysis, ris, points);
+ } else if (mode == 4) {
+ renderIP32Summary(out, buf, analysis, ris, points);
+ } else if (mode == 5) {
+ renderIP24Summary(out, buf, analysis, ris, points);
+ } else if (mode == 6) {
+ renderIP16Summary(out, buf, analysis, ris, points);
+ } else if (mode == 7) {
+ renderPairSummary(out, buf, analysis, ris, points);
+ } else if (mode == 8) {
+ renderCloseSummary(out, buf, analysis, avgMinDist, ris, points);
+ } else if (mode == 9) {
+ renderCloseTmrwSummary(out, buf, analysis, us, avgMinDist, ris, points);
+ } else if (mode == 10) {
+ renderDHTSummary(out, buf, analysis, us, avgMinDist, ris, points);
+ } else if (mode == 11) {
+ renderDestSummary(out, buf, analysis, avgMinDist, ris, points);
+ } else if (mode == 12) {
+ PersistSybil ps = new PersistSybil(_context);
+ try {
+ points = ps.load(date);
+ } catch (IOException ioe) {
+ out.write("No analysis found for " + new Date(date) + "");
+ return;
+ }
+ if (points.isEmpty()) {
+ out.write("No analysis found for " + new Date(date) + "");
+ } else {
+ renderThreatsHTML(out, buf, date, points);
+ }
+ } else if (mode == 13) {
+ long now = _context.clock().now();
+ points = analysis.backgroundAnalysis();
+ if (!points.isEmpty()) {
+ PersistSybil ps = new PersistSybil(_context);
+ try {
+ ps.store(now, points);
+ } catch (IOException ioe) {
+ out.write("Failed to store analysis " + ioe + "");
+ }
+ }
+ renderThreatsHTML(out, buf, now, points);
+ } else {
+ out.write("Unknown mode " + mode);
+ }
+ writeBuf(out, buf);
+ }
+
+ /**
+ * @since 0.9.38
+ */
+ private void renderOverview(Writer out, StringBuilder buf, Analysis analysis) throws IOException {
+ PersistSybil ps = new PersistSybil(_context);
+ List dates = ps.load();
+ if (dates.isEmpty()) {
+ out.write("No stored analysis");
+ } else {
+ buf.append("\n");
+ }
+ buf.append("
Run new analysis");
+ writeBuf(out, buf);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderFFSummary(Writer out, StringBuilder buf, List ris, double avgMinDist) throws IOException {
+ renderRouterInfo(buf, _context.router().getRouterInfo(), null, true, false);
+ buf.append("Known Floodfills: ").append(ris.size()).append("
");
buf.append("\n" +
"Average closest floodfill distance: ").append(fmt.format(avgMinDist)).append("
\n" +
"Routing Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData()))
@@ -156,56 +254,119 @@ public class SybilRenderer {
"Next Routing Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData()))
.append("\" Rotates in: ").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight())).append("\n" +
"
\n");
+ writeBuf(out, buf);
+ }
- Map points = new HashMap(64);
-
- // IP analysis
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderFamilySummary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
Map> fmap = analysis.calculateIPGroupsFamily(ris, points);
renderIPGroupsFamily(out, buf, fmap);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderIPUsSummary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
List ri32 = new ArrayList(4);
List ri24 = new ArrayList(4);
List ri16 = new ArrayList(4);
analysis.calculateIPGroupsUs(ris, points, ri32, ri24, ri16);
renderIPGroupsUs(out, buf, ri32, ri24, ri16);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderIP32Summary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
Map> map = analysis.calculateIPGroups32(ris, points);
renderIPGroups32(out, buf, map);
- map = analysis.calculateIPGroups24(ris, points);
- renderIPGroups24(out, buf, map);
- map = analysis.calculateIPGroups16(ris, points);
- //renderIPGroups16(out, buf, map);
+ }
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderIP24Summary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
+ Map> map = analysis.calculateIPGroups24(ris, points);
+ renderIPGroups24(out, buf, map);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderIP16Summary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
+ Map> map = analysis.calculateIPGroups16(ris, points);
+ renderIPGroups16(out, buf, map);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderPairSummary(Writer out, StringBuilder buf, Analysis analysis, List ris, Map points) throws IOException {
// Pairwise distance analysis
List pairs = new ArrayList(PAIRMAX);
double avg = analysis.calculatePairDistance(ris, points, pairs);
renderPairDistance(out, buf, pairs, avg);
+ }
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderCloseSummary(Writer out, StringBuilder buf, Analysis analysis, double avgMinDist, List ris, Map points) throws IOException {
// Distance to our router analysis
buf.append("Closest Floodfills to Our Routing Key (Where we Store our RI)
");
buf.append("See all
");
+ Hash ourRKey = _context.router().getRouterInfo().getRoutingKey();
analysis.calculateRouterInfo(ourRKey, "our rkey", ris, points);
renderRouterInfoHTML(out, buf, ourRKey, avgMinDist, ris);
+ }
+
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderCloseTmrwSummary(Writer out, StringBuilder buf, Analysis analysis, Hash us, double avgMinDist, List ris, Map points) throws IOException {
+ // Distance to our router analysis
RouterKeyGenerator rkgen = _context.routerKeyGenerator();
Hash nkey = rkgen.getNextRoutingKey(us);
buf.append("Closest Floodfills to Tomorrow's Routing Key (Where we will Store our RI)
");
buf.append("See all
");
analysis.calculateRouterInfo(nkey, "our rkey (tomorrow)", ris, points);
renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris);
+ }
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderDHTSummary(Writer out, StringBuilder buf, Analysis analysis, Hash us, double avgMinDist, List ris, Map points) throws IOException {
buf.append("Closest Floodfills to Our Router Hash (DHT Neighbors if we are Floodfill)
");
analysis.calculateRouterInfo(us, "our router", ris, points);
renderRouterInfoHTML(out, buf, us, avgMinDist, ris);
+ }
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderDestSummary(Writer out, StringBuilder buf, Analysis analysis, double avgMinDist, List ris, Map points) throws IOException {
// Distance to our published destinations analysis
+ RouterKeyGenerator rkgen = _context.routerKeyGenerator();
buf.append("Floodfills Close to Our Destinations
");
Map clientInboundPools = _context.tunnelManager().getInboundClientPools();
List destinations = new ArrayList(clientInboundPools.keySet());
- //boolean debug = _context.getBooleanProperty(HelperBase.PROP_ADVANCED);
+ for (Iterator iter = destinations.iterator(); iter.hasNext(); ) {
+ Hash client = iter.next();
+ if (!_context.clientManager().isLocal(client) ||
+ !_context.clientManager().shouldPublishLeaseSet(client) ||
+ _context.netDb().lookupLeaseSetLocally(client) == null) {
+ iter.remove();
+ }
+ }
+ if (destinations.isEmpty()) {
+ buf.append("None
");
+ writeBuf(out, buf);
+ return;
+ }
for (Hash client : destinations) {
- boolean isLocal = _context.clientManager().isLocal(client);
- if (!isLocal)
- continue;
- if (! _context.clientManager().shouldPublishLeaseSet(client))
- continue;
LeaseSet ls = _context.netDb().lookupLeaseSetLocally(client);
if (ls == null)
continue;
@@ -216,21 +377,22 @@ public class SybilRenderer {
buf.append("See all
");
analysis.calculateRouterInfo(rkey, name, ris, points);
renderRouterInfoHTML(out, buf, rkey, avgMinDist, ris);
- nkey = rkgen.getNextRoutingKey(ls.getHash());
+ Hash nkey = rkgen.getNextRoutingKey(ls.getHash());
buf.append("Closest floodfills to Tomorrow's Routing Key for " + name + " (where we will store our LS)
");
buf.append("See all
");
analysis.calculateRouterInfo(nkey, name + " (tomorrow)", ris, points);
renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris);
}
+ }
- // Profile analysis
- analysis.addProfilePoints(ris, points);
- analysis.addVersionPoints(ris, points);
-
+ /**
+ * @since 0.9.38 split out from renderRouterInfoHTML()
+ */
+ private void renderThreatsHTML(Writer out, StringBuilder buf, long date, Map points) throws IOException {
if (!points.isEmpty()) {
List warns = new ArrayList(points.keySet());
Collections.sort(warns, new PointsComparator(points));
- buf.append("Routers with Most Threat Points
");
+ buf.append("Routers with Most Threat Points as of " + new Date(date) + "
");
for (Hash h : warns) {
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(h);
if (ri == null)
@@ -253,10 +415,7 @@ public class SybilRenderer {
renderRouterInfo(buf, ri, null, false, false);
}
}
-
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -277,10 +436,7 @@ public class SybilRenderer {
renderRouterInfo(buf, p.r1, null, false, false);
renderRouterInfo(buf, p.r2, null, false, false);
}
-
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
private static class FooComparator implements Comparator, Serializable {
@@ -340,9 +496,7 @@ public class SybilRenderer {
}
if (!found)
buf.append("None
");
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -372,9 +526,7 @@ public class SybilRenderer {
}
if (!found)
buf.append("None
");
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -403,9 +555,7 @@ public class SybilRenderer {
}
if (!found)
buf.append("None
");
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -435,9 +585,7 @@ public class SybilRenderer {
}
if (!found)
buf.append("None
");
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -467,9 +615,7 @@ public class SybilRenderer {
if (!found)
buf.append("None
");
buf.append("
");
- out.write(buf.toString());
- out.flush();
- buf.setLength(0);
+ writeBuf(out, buf);
}
/**
@@ -520,6 +666,10 @@ public class SybilRenderer {
" MEDIAN: " + fmt.format(median) +
" MAX: " + fmt.format(max) +
"
\n");
+ writeBuf(out, buf);
+ }
+
+ private static void writeBuf(Writer out, StringBuilder buf) throws IOException {
out.write(buf.toString());
out.flush();
buf.setLength(0);
diff --git a/apps/routerconsole/jsp/netdb.jsp b/apps/routerconsole/jsp/netdb.jsp
index 6c940f615a..1f098523bb 100644
--- a/apps/routerconsole/jsp/netdb.jsp
+++ b/apps/routerconsole/jsp/netdb.jsp
@@ -38,5 +38,7 @@
" />
" />
" />
+ " />
+ " />