From cae5dcd69c0701d29b71bd11bb1927cbf111a0d2 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Mon, 17 Dec 2018 11:23:08 +0000 Subject: [PATCH] Sybil: Refactoring part 6 Make Analysis class a JobImpl, run on configured frequency Bug fixes and cleanups --- .../src/net/i2p/router/sybil/Analysis.java | 84 +++++++++++++++---- .../java/src/net/i2p/router/sybil/Points.java | 5 +- .../i2p/router/web/helpers/SybilRenderer.java | 11 +-- 3 files changed, 76 insertions(+), 24 deletions(-) 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 632baae09d..a6b1cd31af 100644 --- a/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java +++ b/apps/routerconsole/java/src/net/i2p/router/sybil/Analysis.java @@ -1,5 +1,6 @@ package net.i2p.router.sybil; +import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; import java.text.DecimalFormat; @@ -21,6 +22,7 @@ import net.i2p.data.LeaseSet; import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; import net.i2p.data.router.RouterKeyGenerator; +import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.app.RouterApp; @@ -33,6 +35,8 @@ import net.i2p.router.web.Messages; import net.i2p.stat.Rate; import net.i2p.stat.RateAverages; import net.i2p.stat.RateStat; +import net.i2p.util.Addresses; +import net.i2p.util.Log; import net.i2p.util.ObjectCounter; /** @@ -40,13 +44,16 @@ import net.i2p.util.ObjectCounter; * @since 0.9.38 split out from SybilRenderer * */ -public class Analysis implements RouterApp { +public class Analysis extends JobImpl implements RouterApp { private final RouterContext _context; + private final Log _log; private final ClientAppManager _cmgr; private final PersistSybil _persister; private volatile ClientAppState _state = UNINITIALIZED; private final DecimalFormat fmt = new DecimalFormat("#0.00"); + private boolean _wasRun; + /** * The name we register with the ClientAppManager */ @@ -80,7 +87,9 @@ public class Analysis implements RouterApp { /** Get via getInstance() */ private Analysis(RouterContext ctx, ClientAppManager mgr, String[] args) { + super(ctx); _context = ctx; + _log = ctx.logManager().getLog(Analysis.class); _cmgr = mgr; _persister = new PersistSybil(ctx); } @@ -102,6 +111,27 @@ public class Analysis implements RouterApp { public PersistSybil getPersister() { return _persister; } + /////// begin Job methods + + public void runJob() { + long now = _context.clock().now(); + _log.info("Running analysis"); + Map<Hash, Points> points = backgroundAnalysis(); + if (!points.isEmpty()) { + try { + _log.info("Storing analysis"); + _persister.store(now, points); + _log.info("Store complete"); + } catch (IOException ioe) { + _log.error("Failed to store analysis", ioe); + } + } + schedule(); + } + + /////// end Job methods + /////// begin ClientApp methods + /** * ClientApp interface */ @@ -143,22 +173,25 @@ public class Analysis implements RouterApp { _cmgr.notify(this, state, null, null); } - public void schedule() { + public synchronized void schedule() { long freq = _context.getProperty(PROP_FREQUENCY, 0L); if (freq > 0) { List<Long> previous = _persister.load(); - long now = _context.clock().now(); + long now = _context.clock().now() + 15*1000; + if (freq < MIN_FREQUENCY) + freq = MIN_FREQUENCY; long when; - if (!previous.isEmpty()) { - if (freq < MIN_FREQUENCY) - freq = MIN_FREQUENCY; + if (_wasRun) { + when = now + freq; + } else if (!previous.isEmpty()) { when = Math.max(previous.get(0).longValue() + freq, now); } else { when = now; } long up = _context.router().getUptime(); when = Math.max(when, now + MIN_UPTIME - up); - // TODO schedule for when + getTiming().setStartAfter(when); + _context.jobQueue().addJob(this); } } @@ -239,12 +272,17 @@ public class Analysis implements RouterApp { * Return separate maps for each cause instead? * @since 0.9.38 */ - public Map<Hash, Points> backgroundAnalysis() { + public synchronized Map<Hash, Points> backgroundAnalysis() { + _wasRun = true; + Map<Hash, Points> points = new HashMap<Hash, Points>(64); Hash us = _context.routerHash(); + if (us == null) + return points; List<RouterInfo> ris = getFloodfills(us); + if (ris.isEmpty()) + return points; double avgMinDist = getAvgMinDist(ris); - Map<Hash, Points> points = new HashMap<Hash, Points>(64); // IP analysis calculateIPGroupsFamily(ris, points); @@ -375,8 +413,14 @@ public class Analysis implements RouterApp { List<RouterInfo> ri32, List<RouterInfo> ri24, List<RouterInfo> ri16) { RouterInfo us = _context.router().getRouterInfo(); byte[] ourIP = getIP(us); - if (ourIP == null) - return; + if (ourIP == null) { + String last = _context.getProperty("i2np.lastIP"); + if (last == null) + return; + ourIP = Addresses.getIP(last); + if (ourIP == null) + return; + } for (RouterInfo info : ris) { byte[] ip = getIP(info); if (ip == null) @@ -385,11 +429,14 @@ public class Analysis implements RouterApp { if (ip[2] == ourIP[2]) { if (ip[3] == ourIP[3]) { addPoints(points, info.getHash(), POINTS_US32, "Same IP as us"); + ri32.add(info); } else { addPoints(points, info.getHash(), POINTS_US24, "Same /24 as us"); + ri24.add(info); } } else { addPoints(points, info.getHash(), POINTS_US16, "Same /16 as us"); + ri16.add(info); } } } @@ -416,11 +463,13 @@ public class Analysis implements RouterApp { for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) { Integer ii = e.getKey(); int count = oc.count(ii); + double point = POINTS32 * (count - 1); int i = ii.intValue(); int i0 = (i >> 24) & 0xff; int i1 = (i >> 16) & 0xff; int i2 = (i >> 8) & 0xff; int i3 = i & 0xff; + String reason = "Same IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""); for (RouterInfo info : ris) { byte[] ip = getIP(info); if (ip == null) @@ -434,8 +483,7 @@ public class Analysis implements RouterApp { if ((ip[3] & 0xff) != i3) continue; e.getValue().add(info); - double point = POINTS32 * (count - 1); - addPoints(points, info.getHash(), point, "Same IP with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); + addPoints(points, info.getHash(), point, reason); } } return rv; @@ -462,10 +510,12 @@ public class Analysis implements RouterApp { for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) { Integer ii = e.getKey(); int count = oc.count(ii); + double point = POINTS24 * (count - 1); int i = ii.intValue(); int i0 = i >> 16; int i1 = (i >> 8) & 0xff; int i2 = i & 0xff; + String reason = "Same /24 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""); for (RouterInfo info : ris) { byte[] ip = getIP(info); if (ip == null) @@ -477,8 +527,7 @@ public class Analysis implements RouterApp { if ((ip[2] & 0xff) != i2) continue; e.getValue().add(info); - double point = POINTS24 * (count - 1); - addPoints(points, info.getHash(), point, "Same /24 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); + addPoints(points, info.getHash(), point, reason); } } return rv; @@ -505,9 +554,11 @@ public class Analysis implements RouterApp { for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) { Integer ii = e.getKey(); int count = oc.count(ii); + double point = POINTS16 * (count - 1); int i = ii.intValue(); int i0 = i >> 8; int i1 = i & 0xff; + String reason = "Same /16 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""); for (RouterInfo info : ris) { byte[] ip = getIP(info); if (ip == null) @@ -517,8 +568,7 @@ public class Analysis implements RouterApp { if ((ip[1] & 0xff) != i1) continue; e.getValue().add(info); - double point = POINTS16 * (count - 1); - addPoints(points, info.getHash(), point, "Same /16 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : "")); + addPoints(points, info.getHash(), point, reason); } } return rv; diff --git a/apps/routerconsole/java/src/net/i2p/router/sybil/Points.java b/apps/routerconsole/java/src/net/i2p/router/sybil/Points.java index 7386fe2e0d..769ed72a13 100644 --- a/apps/routerconsole/java/src/net/i2p/router/sybil/Points.java +++ b/apps/routerconsole/java/src/net/i2p/router/sybil/Points.java @@ -92,10 +92,11 @@ public class Points implements Comparable<Points> { } catch (NumberFormatException nfe) { return null; } - Points rv = new Points(d, ss[1]); - for (int i = 2; i < ss.length; i++) { + Points rv = new Points(); + for (int i = 1; i < ss.length; i++) { rv.reasons.add(ss[i]); } + rv.points = d; return rv; } } 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 d7a96a5d0f..c808876332 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 @@ -200,7 +200,7 @@ public class SybilRenderer { try { ps.store(now, points); } catch (IOException ioe) { - out.write("<b>Failed to store analysis " + ioe + "</b>"); + out.write("<b>Failed to store analysis: " + ioe + "</b>"); } } renderThreatsHTML(out, buf, now, points); @@ -392,6 +392,7 @@ public class SybilRenderer { if (!points.isEmpty()) { List<Hash> warns = new ArrayList<Hash>(points.keySet()); Collections.sort(warns, new PointsComparator(points)); + ReasonComparator rcomp = new ReasonComparator(); buf.append("<h3 id=\"threats\" class=\"sybils\">Routers with Most Threat Points as of " + new Date(date) + "</h3>"); for (Hash h : warns) { RouterInfo ri = _context.netDb().lookupRouterInfoLocally(h); @@ -404,12 +405,12 @@ public class SybilRenderer { buf.append("<p class=\"threatpoints\"><b>Threat Points: " + fmt.format(p) + "</b></p><ul>"); List<String> reasons = pp.getReasons(); if (reasons.size() > 1) - Collections.sort(reasons, new ReasonComparator()); + Collections.sort(reasons, rcomp); for (String s : reasons) { int c = s.indexOf(':'); if (c <= 0) continue; - buf.append("<li><b>").append(s.substring(0, c+1)).append("</b>").append(s.substring(c+1)).append("</li>"); + buf.append("<li><b>").append(s, 0, c+1).append("</b>").append(s, c+1, s.length()).append("</li>"); } buf.append("</ul>"); renderRouterInfo(buf, ri, null, false, false); @@ -695,7 +696,7 @@ public class SybilRenderer { */ private double renderRouterInfo(StringBuilder buf, RouterInfo info, Hash us, boolean isUs, boolean full) { String hash = info.getIdentity().getHash().toBase64(); - buf.append("<a name=\"").append(hash.substring(0, 6)).append("\"></a><table class=\"sybil_routerinfo\"><tr>"); + buf.append("<a name=\"").append(hash, 0, 6).append("\"></a><table class=\"sybil_routerinfo\"><tr>"); double distance = 0; if (isUs) { buf.append("<th colspan=\"2\"><a name=\"our-info\" ></a><b>" + _t("Our info") + ":</b> <code>").append(hash) @@ -713,7 +714,7 @@ public class SybilRenderer { } if (!full) { buf.append("<a title=\"View extended router info\" class=\"viewfullentry\" href=\"netdb?r=") - .append(hash.substring(0, 6)).append("\" >[").append(_t("Full entry")).append("]</a></th><th>"); + .append(hash, 0, 6).append("\" >[").append(_t("Full entry")).append("]</a></th><th>"); } if (_context.portMapper().isRegistered("imagegen")) buf.append("<img src=\"/imagegen/id?s=32&c=" + hash.replace("=", "%3d") + "\" height=\"32\" width=\"32\"> "); -- GitLab