This commit is contained in:
zab2
2019-03-28 18:57:42 +00:00
parent 85db853d74
commit d90fc421fd
12 changed files with 144 additions and 1 deletions

View File

@ -4,14 +4,32 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
/**
* Counts connection attempts and decides if specified thresholds have been
* breached.
*
* @since 0.9.40
*/
class AccessCounter { class AccessCounter {
/**
* List of timestamps of each connection attempt
*/
private final List<Long> accesses = new ArrayList<Long>(); private final List<Long> accesses = new ArrayList<Long>();
/**
* records that a connection attempt was made
*
* @param now the current time
*/
void recordAccess(long now) { void recordAccess(long now) {
accesses.add(now); accesses.add(now);
} }
/**
* @param threshold definition of a threshold
* @return true if the given threshold has been breached
*/
boolean isBreached(Threshold threshold) { boolean isBreached(Threshold threshold) {
if (threshold.getConnections() == 0) if (threshold.getConnections() == 0)
return !accesses.isEmpty(); return !accesses.isEmpty();

View File

@ -22,6 +22,20 @@ import net.i2p.data.Hash;
import net.i2p.i2ptunnel.I2PTunnelTask; import net.i2p.i2ptunnel.I2PTunnelTask;
import net.i2p.client.streaming.IncomingConnectionFilter; import net.i2p.client.streaming.IncomingConnectionFilter;
/**
* A filter for incoming connections which can be configured
* based on access list rules.
*
* It keeps a track of known destinations - those defined in existing access
* lists and unknown ones - those who are not defined in such lists but have
* recently attempted to connect to us.
*
* Every SYNC_INTERVAL seconds the access lists are reloaded from disk which
* allows the user to edit them. Also, if any recorders are defined in the
* access rules, they will write to disk at such interval.
*
* @since 0.9.40
*/
class AccessFilter implements IncomingConnectionFilter { class AccessFilter implements IncomingConnectionFilter {
private static final long PURGE_INTERVAL = 1000; private static final long PURGE_INTERVAL = 1000;
@ -40,6 +54,11 @@ class AccessFilter implements IncomingConnectionFilter {
*/ */
private final Map<Hash, DestTracker> unknownDests = new HashMap<Hash, DestTracker>(); private final Map<Hash, DestTracker> unknownDests = new HashMap<Hash, DestTracker>();
/**
* @param context the context, used for scheduling and timer purposes
* @param definition definition of this filter
* @param task the task to query for liveness of the tunnel
*/
AccessFilter(I2PAppContext context, FilterDefinition definition, I2PTunnelTask task) AccessFilter(I2PAppContext context, FilterDefinition definition, I2PTunnelTask task)
throws IOException { throws IOException {
this.context = context; this.context = context;
@ -56,7 +75,7 @@ class AccessFilter implements IncomingConnectionFilter {
public boolean allowDestination(Destination d) { public boolean allowDestination(Destination d) {
Hash hash = d.getHash(); Hash hash = d.getHash();
long now = context.clock().now(); long now = context.clock().now();
DestTracker tracker = null; DestTracker tracker;
synchronized(knownDests) { synchronized(knownDests) {
tracker = knownDests.get(hash); tracker = knownDests.get(hash);
} }

View File

@ -7,8 +7,22 @@ import java.io.File;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
/**
* Utility class for parsing filter definitions
*
* @since 0.9.40
*/
class DefinitionParser { class DefinitionParser {
/**
* Processes an array of String objects containing the human-readable definition of
* the filter.
*
* TODO: format
*
* @return a FilterDefinition POJO representation for internal use
* @throws InvalidDefinitionException if the definition is malformed
*/
static FilterDefinition parse(String []definition) throws InvalidDefinitionException { static FilterDefinition parse(String []definition) throws InvalidDefinitionException {
DefinitionBuilder builder = new DefinitionBuilder(); DefinitionBuilder builder = new DefinitionBuilder();

View File

@ -2,12 +2,21 @@ package net.i2p.i2ptunnel.access;
import net.i2p.data.Hash; import net.i2p.data.Hash;
/**
* Tracks the connection attempts for a given remote Destination
*
* @since 0.9.40
*/
class DestTracker { class DestTracker {
private final Hash hash; private final Hash hash;
private final Threshold threshold; private final Threshold threshold;
private final AccessCounter counter; private final AccessCounter counter;
/**
* @param hash hash of the remote destination
* @param threshold threshold defined in the access rule
*/
DestTracker(Hash hash, Threshold threshold) { DestTracker(Hash hash, Threshold threshold) {
this.hash = hash; this.hash = hash;
this.threshold = threshold; this.threshold = threshold;

View File

@ -4,10 +4,21 @@ import java.util.Map;
import net.i2p.data.Hash; import net.i2p.data.Hash;
/**
* A filter definition element that includes a single, explicitly defined
* remote destination
*
* @since 0.9.40
*/
class ExplicitFilterDefinitionElement extends FilterDefinitionElement { class ExplicitFilterDefinitionElement extends FilterDefinitionElement {
private final Hash hash; private final Hash hash;
/**
* @param b32 A string with the .b32 representation of the remote destination
* @param threshold threshold to apply to that destination
* @throws InvalidDefinitionException if the b32 string is not valid b32
*/
ExplicitFilterDefinitionElement(String b32, Threshold threshold) throws InvalidDefinitionException { ExplicitFilterDefinitionElement(String b32, Threshold threshold) throws InvalidDefinitionException {
super(threshold); super(threshold);
this.hash = fromBase32(b32); this.hash = fromBase32(b32);

View File

@ -9,10 +9,20 @@ import java.io.IOException;
import net.i2p.data.Hash; import net.i2p.data.Hash;
/**
* An element of filter definition that reads hashes of remote destinations
* from a file.
*
* @since 0.9.40
*/
class FileFilterDefinitionElement extends FilterDefinitionElement { class FileFilterDefinitionElement extends FilterDefinitionElement {
private final File file; private final File file;
/**
* @param file file to read the remote destinations from
* @param threshold threshold to apply to all those destinations
*/
FileFilterDefinitionElement(File file, Threshold threshold) { FileFilterDefinitionElement(File file, Threshold threshold) {
super(threshold); super(threshold);
this.file = file; this.file = file;

View File

@ -1,5 +1,12 @@
package net.i2p.i2ptunnel.access; package net.i2p.i2ptunnel.access;
/**
* Definition of an access filter.
*
* This POJO contains the parsed representation from the filter definition file.
*
* @since 0.9.40
*/
class FilterDefinition { class FilterDefinition {
private final Threshold defaultThreshold; private final Threshold defaultThreshold;
@ -7,6 +14,11 @@ class FilterDefinition {
private final Recorder[] recorders; private final Recorder[] recorders;
private final int purgeMinutes; private final int purgeMinutes;
/**
* @param defaultThreshold threshold to apply to unknown remote destinations
* @param elements the elements defined in the filter definition, if any
* @param recorders the recorders defined in the filter definition, if any
*/
FilterDefinition(Threshold defaultThreshold, FilterDefinition(Threshold defaultThreshold,
FilterDefinitionElement[] elements, FilterDefinitionElement[] elements,
Recorder[] recorders) { Recorder[] recorders) {

View File

@ -6,6 +6,11 @@ import java.io.IOException;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.Base32; import net.i2p.data.Base32;
/**
* Base class for elements found in filter definition files
*
* @since 0.9.40
*/
abstract class FilterDefinitionElement { abstract class FilterDefinitionElement {
protected final Threshold threshold; protected final Threshold threshold;
@ -14,12 +19,19 @@ abstract class FilterDefinitionElement {
this.threshold = threshold; this.threshold = threshold;
} }
/**
* Updates the provided map with the hash(es) of remote destinations
* mentioned in this element
*/
abstract void update(Map<Hash, DestTracker> map) throws IOException; abstract void update(Map<Hash, DestTracker> map) throws IOException;
Threshold getThreshold() { Threshold getThreshold() {
return threshold; return threshold;
} }
/**
* Utility method to create a Hash object from a .b32 string
*/
protected static Hash fromBase32(String b32) throws InvalidDefinitionException { protected static Hash fromBase32(String b32) throws InvalidDefinitionException {
if (!b32.endsWith(".b32.i2p")) if (!b32.endsWith(".b32.i2p"))
throw new InvalidDefinitionException("Invalid b32 " + b32); throw new InvalidDefinitionException("Invalid b32 " + b32);

View File

@ -12,7 +12,21 @@ import net.i2p.I2PAppContext;
import net.i2p.i2ptunnel.I2PTunnelTask; import net.i2p.i2ptunnel.I2PTunnelTask;
import net.i2p.client.streaming.IncomingConnectionFilter; import net.i2p.client.streaming.IncomingConnectionFilter;
/**
* Factory for incoming connection filters. Only public class in this package.
*
* @since 0.9.40
*/
public class FilterFactory { public class FilterFactory {
/**
* Creates an instance of IncomingConnectionFilter based on the definition
* contained in the given file.
*
* @param context the context this is running in
* @param definition file containing the filter definition
* @param task the I2PTunnelTask instance to query for liveness
*/
public static IncomingConnectionFilter createFilter(I2PAppContext context, public static IncomingConnectionFilter createFilter(I2PAppContext context,
File definition, File definition,
I2PTunnelTask task) I2PTunnelTask task)

View File

@ -1,5 +1,9 @@
package net.i2p.i2ptunnel.access; package net.i2p.i2ptunnel.access;
/**
* Exception thrown if the filter definition file cannot be
* parsed for some reason.
*/
public class InvalidDefinitionException extends Exception { public class InvalidDefinitionException extends Exception {
public InvalidDefinitionException(String reason) { public InvalidDefinitionException(String reason) {
super(reason); super(reason);

View File

@ -2,11 +2,22 @@ package net.i2p.i2ptunnel.access;
import java.io.File; import java.io.File;
/**
* Definition of a recorder. If any remote destinations attempt
* enough connections to cause a breach of the specified threshold,
* their hash will be recorded in the specified file.
*
* @since 0.9.40
*/
class Recorder { class Recorder {
private final File file; private final File file;
private final Threshold threshold; private final Threshold threshold;
/**
* @param file to record hashes of destinations that breach the threshold
* @param threshold the threshold that needs to be breached to trigger recording
*/
Recorder(File file, Threshold threshold) { Recorder(File file, Threshold threshold) {
this.file = file; this.file = file;
this.threshold = threshold; this.threshold = threshold;

View File

@ -1,8 +1,17 @@
package net.i2p.i2ptunnel.access; package net.i2p.i2ptunnel.access;
/**
* Definition of a Threshold.
*
* A Threshold is defined by a number of connections over a period of minutes
*
* @since 0.9.40
*/
class Threshold { class Threshold {
/** A Threshold that is never breached */
static final Threshold ALLOW = new Threshold(Integer.MAX_VALUE, 1); static final Threshold ALLOW = new Threshold(Integer.MAX_VALUE, 1);
/** A Threshold that is always breached */
static final Threshold DENY = new Threshold(0, 1); static final Threshold DENY = new Threshold(0, 1);
private final int connections; private final int connections;