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 0b02a9ca2..919f0624b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java +++ b/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java @@ -65,6 +65,7 @@ public class Analysis extends JobImpl implements RouterApp { public static final String PROP_FREQUENCY = "router.sybilFrequency"; public static final String PROP_THRESHOLD = "router.sybilThreshold"; public static final String PROP_BLOCK = "router.sybilBlock.enable"; + public static final String PROP_NONFF = "router.sybilIncludeAll"; public static final String PROP_BLOCKTIME = "router.sybilBlock.period"; private static final long MIN_FREQUENCY = 60*60*1000L; private static final long MIN_UPTIME = 75*60*1000L; @@ -81,6 +82,7 @@ public class Analysis extends JobImpl implements RouterApp { private static final double POINTS_US24 = 20.0; private static final double POINTS_US16 = 10.0; private static final double POINTS_FAMILY = -10.0; + private static final double POINTS_NONFF = -5.0; private static final double POINTS_BAD_OUR_FAMILY = 100.0; private static final double POINTS_OUR_FAMILY = -100.0; public static final double MIN_CLOSE = 242.0; @@ -126,7 +128,7 @@ public class Analysis extends JobImpl implements RouterApp { public void runJob() { long now = _context.clock().now(); _log.info("Running analysis"); - Map points = backgroundAnalysis(); + Map points = backgroundAnalysis(_context.getBooleanProperty(PROP_NONFF)); if (!points.isEmpty()) { try { _log.info("Storing analysis"); @@ -282,17 +284,30 @@ public class Analysis extends JobImpl implements RouterApp { /** * Analyze threats. No output. * Return separate maps for each cause instead? + * @param includeAll false for floodfills only * @since 0.9.38 */ - public synchronized Map backgroundAnalysis() { + public synchronized Map backgroundAnalysis(boolean includeAll) { _wasRun = true; Map points = new HashMap(64); Hash us = _context.routerHash(); if (us == null) return points; - List ris = getFloodfills(us); + List ris; + if (includeAll) { + Set set = _context.netDb().getRouters(); + ris = new ArrayList(set.size()); + for (RouterInfo ri : set) { + if (!ri.getIdentity().getHash().equals(us)) + ris.add(ri); + } + } else { + ris = getFloodfills(us); + } if (ris.isEmpty()) return points; + if (_log.shouldWarn()) + _log.warn("Analyzing " + ris.size() + " routers, including non-floodfills? " + includeAll); double avgMinDist = getAvgMinDist(ris); @@ -396,8 +411,14 @@ public class Analysis extends JobImpl implements RouterApp { double total = 0; for (int i = 0; i < sz; i++) { RouterInfo info1 = ris.get(i); + // don't do distance calculation for non-floodfills + if (!info1.getCapabilities().contains("f")) + continue; for (int j = i + 1; j < sz; j++) { RouterInfo info2 = ris.get(j); + // don't do distance calculation for non-floodfills + if (!info2.getCapabilities().contains("f")) + continue; BigInteger dist = HashDistance.getDistance(info1.getHash(), info2.getHash()); if (pairs.isEmpty()) { pairs.add(new Pair(info1, info2, dist)); @@ -699,6 +720,9 @@ public class Analysis extends JobImpl implements RouterApp { } addPoints(points, h, POINTS_BANLIST, buf.toString()); } + // don't do profile calcluations for non-floodfills + if (!info.getCapabilities().contains("f")) + continue; PeerProfile prof = _context.profileOrganizer().getProfileNonblocking(h); if (prof != null) { long heard = prof.getFirstHeardAbout(); @@ -748,6 +772,8 @@ public class Analysis extends JobImpl implements RouterApp { String caps = info.getCapabilities(); if (!caps.contains("R")) addPoints(points, h, POINTS_UNREACHABLE, "Unreachable: " + DataHelper.escapeHTML(caps)); + if (!caps.contains("f")) + addPoints(points, h, POINTS_NONFF, "Non-floodfill"); String hisFullVer = info.getVersion(); if (!hisFullVer.startsWith("0.9.")) { addPoints(points, h, POINTS_BAD_VERSION, "Strange version " + DataHelper.escapeHTML(hisFullVer)); @@ -779,6 +805,9 @@ public class Analysis extends JobImpl implements RouterApp { int count = Math.min(MAX, ris.size()); for (int i = 0; i < count; i++) { RouterInfo ri = ris.get(i); + // don't do distance calculation for non-floodfills + if (!ri.getCapabilities().contains("f")) + continue; BigInteger bidist = HashDistance.getDistance(us, ri.getHash()); double dist = biLog2(bidist); double point = MIN_CLOSE - dist; 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 98ee56e5a..ccdb51c0f 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 @@ -242,6 +242,8 @@ public class NetDbHelper extends FormHandler { } String enable = getJettyString("block"); toSave.put(Analysis.PROP_BLOCK, Boolean.toString(enable != null)); + String nonff = getJettyString("nonff"); + toSave.put(Analysis.PROP_NONFF, Boolean.toString(nonff != null)); if (_context.router().saveConfig(toSave, null)) addFormNotice(_t("Configuration saved successfully.")); else @@ -273,7 +275,7 @@ public class NetDbHelper extends FormHandler { } else if (_full == 3) { if (_mode == 12 && !_postOK) _mode = 0; - else if (_mode == 13 && !_postOK) + else if ((_mode == 13 || _mode == 16) && !_postOK) _mode = 14; (new SybilRenderer(_context)).getNetDbSummary(_out, _newNonce, _mode, _date); } else if (_full == 4) { 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 fbd734693..11dbcc450 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 @@ -134,7 +134,7 @@ public class SybilRenderer { Hash us = _context.routerHash(); Analysis analysis = Analysis.getInstance(_context); List ris = null; - if (mode != 0 && mode != 12 && mode != 13 && mode != 14) { + if (mode != 0 && mode != 12 && mode != 13 && mode != 14 && mode != 16) { ris = analysis.getFloodfills(us); if (ris.isEmpty()) { out.write("

No known floodfills

"); @@ -208,10 +208,10 @@ public class SybilRenderer { } else { renderThreatsHTML(out, buf, date, points); } - } else if (mode == 13) { + } else if (mode == 13 || mode == 16) { // run analysis and store it long now = _context.clock().now(); - points = analysis.backgroundAnalysis(); + points = analysis.backgroundAnalysis(mode == 16); if (!points.isEmpty()) { PersistSybil ps = analysis.getPersister(); try { @@ -273,6 +273,14 @@ public class SybilRenderer { "\n" + "\n" + "" + + "(floodfills only)" + + "
\n"); + buf.append("
\n" + + "\n" + + "\n" + + "\n" + + "" + + "(all routers)" + "
\n"); writeBuf(out, buf); } @@ -302,12 +310,17 @@ public class SybilRenderer { buf.append("\n"); } boolean auto = _context.getBooleanProperty(Analysis.PROP_BLOCK); + boolean nonff = _context.getBooleanProperty(Analysis.PROP_NONFF); String thresh = _context.getProperty(Analysis.PROP_THRESHOLD, "50"); long days = _context.getProperty(Analysis.PROP_BLOCKTIME, 7*24*60*60*1000L) / (24*60*60*1000L); buf.append("\n" + "Auto-block routers?\n" + + "Include non-floodfills?\n" + "Minimum threat points to block:\n" + "Days to block:\n" +