forked from I2P_Developers/i2p.i2p
Sybil: Persist blocklist
This commit is contained in:
@@ -8,6 +8,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -16,6 +17,7 @@ import java.util.Set;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
@@ -24,6 +26,7 @@ import net.i2p.data.router.RouterAddress;
|
||||
import net.i2p.data.router.RouterInfo;
|
||||
import net.i2p.data.router.RouterKeyGenerator;
|
||||
import net.i2p.router.Banlist;
|
||||
import net.i2p.router.Blocklist;
|
||||
import net.i2p.router.JobImpl;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.TunnelPoolSettings;
|
||||
@@ -129,6 +132,38 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
|
||||
public PersistSybil getPersister() { return _persister; }
|
||||
|
||||
/**
|
||||
* Load the persisted blocklist and tell the router
|
||||
*
|
||||
* @since 0.9.50
|
||||
*/
|
||||
private class InitJob extends JobImpl {
|
||||
public InitJob() { super(_context); }
|
||||
|
||||
public String getName() { return "Load Sybil Blocklist"; }
|
||||
|
||||
public void runJob() {
|
||||
Map<String, Long> map = _persister.readBlocklist();
|
||||
if (map == null || map.isEmpty())
|
||||
return;
|
||||
Blocklist bl = _context.blocklist();
|
||||
Banlist ban = _context.banlist();
|
||||
for (Map.Entry<String, Long> e : map.entrySet()) {
|
||||
String s = e.getKey();
|
||||
if (s.contains(".") || s.contains(":")) {
|
||||
bl.add(s);
|
||||
} else {
|
||||
byte[] b = Base64.decode(s);
|
||||
if (b != null && b.length == Hash.HASH_LENGTH) {
|
||||
Hash h = Hash.create(b);
|
||||
long until = e.getValue().longValue();
|
||||
ban.banlistRouter(h, "Sybil analysis", null, null, until);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////// begin Job methods
|
||||
|
||||
public void runJob() {
|
||||
@@ -159,6 +194,10 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
changeState(RUNNING);
|
||||
_cmgr.register(this);
|
||||
_persister.removeOld();
|
||||
InitJob init = new InitJob();
|
||||
long start = _context.clock().now() + 5*1000;
|
||||
init.getTiming().setStartAfter(start);
|
||||
_context.jobQueue().addJob(init);
|
||||
schedule();
|
||||
}
|
||||
|
||||
@@ -395,16 +434,21 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
threshold = MIN_BLOCK_POINTS;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
String day = DataHelper.formatTime(now);
|
||||
Set<String> blocks = new HashSet<String>();
|
||||
for (Map.Entry<Hash, Points> e : points.entrySet()) {
|
||||
double p = e.getValue().getPoints();
|
||||
if (p >= threshold) {
|
||||
Hash h = e.getKey();
|
||||
blocks.add(h.toBase64());
|
||||
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(h);
|
||||
if (ri != null) {
|
||||
for (RouterAddress ra : ri.getAddresses()) {
|
||||
byte[] ip = ra.getIP();
|
||||
if (ip != null)
|
||||
_context.blocklist().add(ip);
|
||||
_context.blocklist().add(ip);
|
||||
String host = ra.getHost();
|
||||
if (host != null)
|
||||
blocks.add(host);
|
||||
}
|
||||
}
|
||||
String reason = "Sybil analysis " + day + " with " + fmt.format(p) + " threat points";
|
||||
@@ -417,6 +461,8 @@ public class Analysis extends JobImpl implements RouterApp {
|
||||
_context.banlist().banlistRouter(h, reason, null, null, blockUntil);
|
||||
}
|
||||
}
|
||||
if (!blocks.isEmpty())
|
||||
_persister.storeBlocklist(blocks, blockUntil);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
@@ -41,9 +42,11 @@ public class PersistSybil {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
|
||||
private static final String DIR = "sybil-analysis/results";
|
||||
private static final String SDIR = "sybil-analysis";
|
||||
private static final String DIR = SDIR + "/results";
|
||||
private static final String PFX = "sybil-";
|
||||
private static final String SFX = ".txt.gz";
|
||||
private static final String BLOCKLIST_SYBIL_FILE = "blocklist-sybil.txt";
|
||||
|
||||
/** access via Analysis.getPersister() */
|
||||
PersistSybil(I2PAppContext ctx) {
|
||||
@@ -229,6 +232,101 @@ public class PersistSybil {
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the blocklist
|
||||
*
|
||||
* @return map of ip or hash to expiration (ms), or null on failure
|
||||
* @since 0.9.50
|
||||
*/
|
||||
Map<String, Long> readBlocklist() {
|
||||
File f = new File(_context.getConfigDir(), SDIR);
|
||||
f = new File(f, BLOCKLIST_SYBIL_FILE);
|
||||
return readBlocklist(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the blocklist
|
||||
*
|
||||
* @return map of ip or hash to expiration (ms), or null on failure
|
||||
* @since 0.9.50
|
||||
*/
|
||||
private synchronized Map<String, Long> readBlocklist(File blFile) {
|
||||
Map<String, Long> rv = null;
|
||||
if (blFile.exists()) {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream(blFile), "UTF-8"));
|
||||
rv = new HashMap<String, Long>();
|
||||
String buf = null;
|
||||
long now = _context.clock().now() + 5*60*1000L;
|
||||
while ((buf = br.readLine()) != null) {
|
||||
int index = buf.indexOf('#');
|
||||
if (index == 0)
|
||||
continue;
|
||||
String[] ss = DataHelper.split(buf, ",", 2);
|
||||
if (ss.length != 2)
|
||||
continue;
|
||||
try {
|
||||
long exp = Long.parseLong(ss[1]);
|
||||
if (exp < now)
|
||||
continue;
|
||||
rv.put(ss[0], Long.valueOf(exp));
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Error reading the blocklist file", ioe);
|
||||
} finally {
|
||||
if (br != null) try { br.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the blocklist.
|
||||
* The format is different than other blocklists because we include an expiration.
|
||||
* Format: One per line: ip or hash,expiration time (ms)
|
||||
*
|
||||
* @param blocks non-empty, will be merged with existing entries
|
||||
* @since 0.9.50
|
||||
*/
|
||||
synchronized void storeBlocklist(Set<String> blocks, long blockUntil) {
|
||||
File dir = new SecureDirectory(_context.getConfigDir(), SDIR);
|
||||
if (!dir.exists())
|
||||
dir.mkdirs();
|
||||
File blFile = new File(dir, BLOCKLIST_SYBIL_FILE);
|
||||
Map<String, Long> map = readBlocklist(blFile);
|
||||
if (map == null)
|
||||
map = new HashMap<String, Long>();
|
||||
Long until = Long.valueOf(blockUntil);
|
||||
for (String s : blocks) {
|
||||
Long old = map.put(s, until);
|
||||
if (old != null && old.longValue() > blockUntil) {
|
||||
// unlikely
|
||||
map.put(s, old);
|
||||
}
|
||||
}
|
||||
Writer out = null;
|
||||
try {
|
||||
out = new OutputStreamWriter(new SecureFileOutputStream(blFile));
|
||||
out.write("# Format (one per line)\n");
|
||||
out.write("# IP or Base64 router hash,expiration (ms)\n");
|
||||
for (Map.Entry<String, Long> e : map.entrySet()) {
|
||||
out.write(e.getKey());
|
||||
out.write(',');
|
||||
out.write(e.getValue().toString());
|
||||
out.write('\n');
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Error writing the blocklist file", ioe);
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
public static void main(String[] args) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
|
||||
Reference in New Issue
Block a user