Sybil: Refactoring part 6

Make Analysis class a JobImpl, run on configured frequency
Bug fixes and cleanups
This commit is contained in:
zzz
2018-12-17 11:23:08 +00:00
parent 2a805dddf5
commit cae5dcd69c
3 changed files with 76 additions and 24 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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&amp;c=" + hash.replace("=", "%3d") + "\" height=\"32\" width=\"32\"> ");