/** * */ package ecologylab.oodss.exceptions; import java.util.HashMap; import ecologylab.generic.Debug; /** * Throw this Exception when we detect that the client is evil or lame. * * @author andruid * */ public class BadClientException extends Exception { /** * */ private static final long serialVersionUID = 1652784829579621254L; private static HashMap<String, EvilHostEntry> evilHostsMap = new HashMap<String, EvilHostEntry>(); /** * Time for which a seemingly evil host gets locked out. Currently 20 minutes. */ public static final long LOCKOUT_INTERVAL = 20 * 60 * 1000; /** * Time in which bad responses from a host define it as evil host. Currently 1 minute. */ public static final long REPEAT_OFFENDER_INTERVAL = 60 * 1000; public static final int BAD_OFFENSE_THRESHOLD = 3; // TODO make all call sites pass IP number in // TODO make call site in timeoutBeforeValidMsg also pass timeStamp in. /** * Report that the client has behaved badly, by sending an improperly formed message. * * @param message */ public BadClientException(String ipNumber, String message) { this(ipNumber, System.currentTimeMillis(), message); } /** * Report that the client has behaved badly, by timing out. * * @param message */ public BadClientException(String ipNumber, long timeStamp, String message) { super(message); badClientIncident(ipNumber, timeStamp); Debug.println(ipNumber + " flagged because " + message); } static class EvilHostEntry { long timeStamp; int count; EvilHostEntry(long timeStamp) { this.timeStamp = timeStamp; } EvilHostEntry() { this(System.currentTimeMillis()); } void badClientIncident(long newTimeStamp) { count++; this.timeStamp = newTimeStamp; } void badClientIncident() { badClientIncident(System.currentTimeMillis()); } boolean isEvil() { return (System.currentTimeMillis() - timeStamp) < LOCKOUT_INTERVAL; } } static class OkEvilHostEntry extends EvilHostEntry { OkEvilHostEntry() { } @Override boolean isEvil() { return false; } } static final EvilHostEntry OK_HOST_ENTRY = new OkEvilHostEntry(); public static boolean isEvilHostByNumber(String ipNumber) { Debug.println("I'm looking up " + ipNumber); for (String s : evilHostsMap.keySet()) { Debug.println(s); } EvilHostEntry entry = evilHostsMap.get(ipNumber); if (entry == null) { synchronized (evilHostsMap) { entry = evilHostsMap.get(ipNumber); if (entry == null) { entry = OK_HOST_ENTRY; evilHostsMap.put(ipNumber, OK_HOST_ENTRY); } } } Debug.println(ipNumber + " is evil? " + entry.isEvil()); return entry.isEvil(); } /** * Register a BadClientException incident for this host. * * @param ipNumber * Host that was bad. * @param timeStamp * When the bad event occurred * * @return true if now the host is considered to be evil. */ private static boolean badClientIncident(String ipNumber, long timeStamp) { Debug.println("client at " + ipNumber + " was naughty and is going into timeout."); EvilHostEntry entry = evilHostsMap.get(ipNumber); if ((entry == null) || (entry == OK_HOST_ENTRY)) { synchronized (evilHostsMap) { entry = evilHostsMap.get(ipNumber); if ((entry == null) || (entry == OK_HOST_ENTRY)) { entry = new EvilHostEntry(timeStamp); evilHostsMap.put(ipNumber, entry); } } } entry.badClientIncident(timeStamp); return entry.isEvil(); } }