forked from I2P_Developers/i2p.i2p
Sybil: Refactoring part 6
Make Analysis class a JobImpl, run on configured frequency Bug fixes and cleanups
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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\"> ");
|
||||
|
Reference in New Issue
Block a user