This is an automated email from the ASF dual-hosted git repository.

elsloo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-trafficcontrol.git

commit f2542e62394fe93d67367c3411c9c6751e51b0dd
Author: PeterRyder <peter.w.ry...@gmail.com>
AuthorDate: Tue Jul 18 13:24:04 2017 -0400

    Initial commit of open source anonymous ip blocking
---
 .../traffic_router/core/config/ConfigHandler.java  |  66 ++++++
 .../traffic_router/core/ds/DeliveryService.java    |   8 +-
 .../traffic_router/core/loc/AnonymousIp.java       | 241 +++++++++++++++++++
 .../core/loc/AnonymousIpConfigUpdater.java         |  53 +++++
 .../core/loc/AnonymousIpDatabaseService.java       | 117 ++++++++++
 .../core/loc/AnonymousIpDatabaseUpdater.java       |  65 ++++++
 .../core/loc/AnonymousIpWhitelist.java             |  48 ++++
 .../traffic_router/core/router/StatTracker.java    |   2 +-
 .../traffic_router/core/router/TrafficRouter.java  |  22 +-
 .../core/router/TrafficRouterManager.java          |   8 +-
 .../src/main/webapp/WEB-INF/applicationContext.xml |  23 ++
 .../core/loc/AnonymousIpDatabaseServiceTest.java   |  81 +++++++
 .../traffic_router/core/loc/AnonymousIpTest.java   | 258 +++++++++++++++++++++
 .../core/loc/AnonymousIpWhitelistTest.java         | 227 ++++++++++++++++++
 .../core/src/test/resources/anonymous_ip.json      |  16 ++
 .../test/resources/anonymous_ip_no_whitelist.json  |  12 +
 16 files changed, 1243 insertions(+), 4 deletions(-)

diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
index ea17db0..aa55f0a 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/config/ConfigHandler.java
@@ -60,6 +60,9 @@ import 
com.comcast.cdn.traffic_control.traffic_router.core.util.TrafficOpsUtils;
 import com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker;
 import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
 import com.comcast.cdn.traffic_control.traffic_router.core.request.HTTPRequest;
+import com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIp;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpConfigUpdater;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpDatabaseUpdater;
 
 @SuppressWarnings("PMD.TooManyFields")
 public class ConfigHandler {
@@ -80,6 +83,8 @@ public class ConfigHandler {
        private DeepNetworkUpdater deepNetworkUpdater;
        private FederationsWatcher federationsWatcher;
        private RegionalGeoUpdater regionalGeoUpdater;
+       private AnonymousIpConfigUpdater anonymousIpConfigUpdater;
+       private AnonymousIpDatabaseUpdater anonymousIpDatabaseUpdater;
        private SteeringWatcher steeringWatcher;
        private CertificatesPoller certificatesPoller;
        private CertificatesPublisher certificatesPublisher;
@@ -112,6 +117,14 @@ public class ConfigHandler {
                return regionalGeoUpdater;
        }
 
+       public AnonymousIpConfigUpdater getAnonymousIpConfigUpdater() {
+               return anonymousIpConfigUpdater;
+       }
+
+       public AnonymousIpDatabaseUpdater getAnonymousIpDatabaseUpdater() {
+               return anonymousIpDatabaseUpdater;
+       }
+
        @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", 
"PMD.AvoidCatchingThrowable"})
        public boolean processConfig(final String jsonStr) throws 
JsonUtilsException, IOException  {
                isProcessing.set(true);
@@ -148,6 +161,7 @@ public class ConfigHandler {
                                parseCoverageZoneNetworkConfig(config);
                                parseDeepCoverageZoneNetworkConfig(config);
                                parseRegionalGeoConfig(jo);
+                               parseAnonymousIpConfig(jo);
 
                                final CacheRegister cacheRegister = new 
CacheRegister();
                                final JsonNode deliveryServicesJson = 
JsonUtils.getJsonNode(jo, "deliveryServices");
@@ -270,6 +284,14 @@ public class ConfigHandler {
                this.regionalGeoUpdater = regionalGeoUpdater;
        }
 
+       public void setAnonymousIpConfigUpdater(final AnonymousIpConfigUpdater 
anonymousIpConfigUpdater) {
+               this.anonymousIpConfigUpdater = anonymousIpConfigUpdater;
+       }
+       
+       public void setAnonymousIpDatabaseUpdater(final 
AnonymousIpDatabaseUpdater anonymousIpDatabaseUpdater) {
+               this.anonymousIpDatabaseUpdater = anonymousIpDatabaseUpdater;
+       }
+
        /**
         * Parses the Traffic Ops config
         * @param config
@@ -540,6 +562,50 @@ public class ConfigHandler {
                }
        }
 
+       private void parseAnonymousIpConfig(final JSONObject jo) throws 
JSONException {
+               final String anonymousPollingUrl = "anonymousip.polling.url";
+               final String anonymousPollingInterval = 
"anonymousip.polling.interval";
+               final String anonymousPolicyConfiguration = 
"anonymousip.policy.configuration";
+               
+               final JSONObject config = jo.getJSONObject("config");
+               final String configUrl = 
config.optString(anonymousPolicyConfiguration, null);
+               final String databaseUrl = 
config.optString(anonymousPollingUrl, null);
+
+               if (configUrl == null) {
+                       LOGGER.info(anonymousPolicyConfiguration + " not 
configured; stopping service updater and disabling feature");
+                       getAnonymousIpConfigUpdater().stopServiceUpdater();
+                       AnonymousIp.getCurrentConfig().enabled = false;
+                       return;
+               }
+               
+               if (databaseUrl == null) {
+                       LOGGER.info(anonymousPollingUrl + " not configured; 
stopping service updater and disabling feature");
+                       getAnonymousIpDatabaseUpdater().stopServiceUpdater();
+                       AnonymousIp.getCurrentConfig().enabled = false;
+                       return;
+               }
+
+               if (jo.has(deliveryServicesKey)) {
+                       final JSONObject dss = 
jo.getJSONObject(deliveryServicesKey);
+                       for (final String ds : JSONObject.getNames(dss)) {
+                               if 
(dss.getJSONObject(ds).has("anonymousBlockingEnabled") &&
+                                               
dss.getJSONObject(ds).getString("anonymousBlockingEnabled").equals("true")) {
+                                       final long interval = 
config.optLong(anonymousPollingInterval);
+                                       
getAnonymousIpConfigUpdater().setDataBaseURL(configUrl, interval);
+                                       
getAnonymousIpDatabaseUpdater().setDataBaseURL(databaseUrl, interval);
+                                       AnonymousIp.getCurrentConfig().enabled 
= true;
+                                       LOGGER.debug("Anonymous Blocking in 
use, scheduling service updaters and enabling feature");
+                                       return;
+                               }
+                       }
+               }
+
+               LOGGER.debug("No DS using anonymous ip blocking - disabling 
feature");
+               getAnonymousIpConfigUpdater().cancelServiceUpdater();
+               getAnonymousIpDatabaseUpdater().cancelServiceUpdater();
+               AnonymousIp.getCurrentConfig().enabled = false;
+       }
+
        /**
         * Parses the ConverageZoneNetwork database configuration and updates 
the database if the URL has
         * changed.
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/DeliveryService.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/DeliveryService.java
index 4aadd70..41637b3 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/DeliveryService.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/DeliveryService.java
@@ -51,7 +51,7 @@ import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Tr
 import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Track.ResultDetails;
 import 
com.comcast.cdn.traffic_control.traffic_router.core.util.StringProtector;
 
-@SuppressWarnings({"PMD.TooManyFields","PMD.CyclomaticComplexity"})
+@SuppressWarnings({"PMD.TooManyFields","PMD.CyclomaticComplexity", 
"PMD.AvoidDuplicateLiterals"})
 public class DeliveryService {
        protected static final Logger LOGGER = 
Logger.getLogger(DeliveryService.class);
        private final String id;
@@ -86,6 +86,7 @@ public class DeliveryService {
        private final Set<String> requestHeaders = new HashSet<String>();
        private final boolean regionalGeoEnabled;
        private final String geolocationProvider;
+       private final boolean anonymousIpEnabled;
        private final boolean sslEnabled;
        private static final int STANDARD_HTTP_PORT = 80;
        private static final int STANDARD_HTTPS_PORT = 443;
@@ -145,6 +146,7 @@ public class DeliveryService {
                        LOGGER.info("DeliveryService '" + id + "' will use 
default geolocation provider Maxmind");
                }
                sslEnabled = JsonUtils.optBoolean(dsJo, "sslEnabled");
+               this.anonymousIpEnabled = JsonUtils.optBoolean(dsJo, 
"anonymousBlockingEnabled");
 
                final JsonNode protocol = dsJo.get("protocol");
                acceptHttp = JsonUtils.optBoolean(protocol, "acceptHttp", true);
@@ -617,6 +619,10 @@ public class DeliveryService {
                return geolocationProvider;
        }
 
+       public boolean isAnonymousIpEnabled() {
+               return anonymousIpEnabled;
+       }
+
        public List<CacheLocation> filterAvailableLocations(final 
Collection<CacheLocation> cacheLocations) {
                final List<CacheLocation> locations = new 
ArrayList<CacheLocation>();
 
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIp.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIp.java
new file mode 100644
index 0000000..bc1452e
--- /dev/null
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIp.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import java.io.File;
+import java.io.FileReader;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+
+import org.apache.log4j.Logger;
+import org.apache.wicket.ajax.json.JSONException;
+import org.apache.wicket.ajax.json.JSONObject;
+import org.apache.wicket.ajax.json.JSONTokener;
+
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.Cache;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.DeliveryService;
+import com.comcast.cdn.traffic_control.traffic_router.core.request.HTTPRequest;
+import com.comcast.cdn.traffic_control.traffic_router.core.request.Request;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.HTTPRouteResult;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Track;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Track.ResultType;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.TrafficRouter;
+import com.google.common.net.InetAddresses;
+import com.maxmind.geoip2.model.AnonymousIpResponse;
+
+public final class AnonymousIp {
+
+       private static final Logger LOGGER = 
Logger.getLogger(AnonymousIp.class);
+
+       private static AnonymousIp currentConfig = new AnonymousIp();
+
+       // Feature flipper
+       // This is set to true if the CRConfig parameters containing the MMDB 
URL
+       // and the config url are present AND any delivery service has the 
feature
+       // enabled
+       public boolean enabled = false;
+
+       private boolean blockAnonymousIp = true;
+       private boolean blockHostingProvider = true;
+       private boolean blockPublicProxy = true;
+       private boolean blockTorExitNode = true;
+
+       private AnonymousIpWhitelist ipv4Whitelist;
+       private AnonymousIpWhitelist ipv6Whitelist;
+
+       public final static int BLOCK_CODE = 403;
+       public final static String WHITE_LIST_LOC = "w";
+
+       private AnonymousIp() {
+               try {
+                       ipv4Whitelist = new AnonymousIpWhitelist();
+                       ipv6Whitelist = new AnonymousIpWhitelist();
+               } catch (NetworkNodeException e) {
+                       LOGGER.error("AnonymousIp ERR: Network node exception 
", e);
+               }
+       }
+
+       /*
+        * Returns the current anonymous ip object
+        */
+       public static AnonymousIp getCurrentConfig() {
+               return currentConfig;
+       }
+
+       /*
+        * Returns the list of subnets in the IPv4 whitelist
+        */
+       public AnonymousIpWhitelist getIPv4Whitelist() {
+               return ipv4Whitelist;
+       }
+
+       /*
+        * Returns the list of subnets in the IPv6 whitelist
+        */
+       public AnonymousIpWhitelist getIPv6Whitelist() {
+               return ipv6Whitelist;
+       }
+
+       private static void parseIPv4Whitelist(final JSONObject config, final 
AnonymousIp anonymousIp) throws JSONException {
+               if (config.optJSONArray("ip4Whitelist") != null) {
+                       try {
+                               anonymousIp.ipv4Whitelist = new 
AnonymousIpWhitelist();
+                               
anonymousIp.ipv4Whitelist.init(config.optJSONArray("ip4Whitelist"));
+                       } catch (NetworkNodeException e) {
+                               LOGGER.error("Anonymous Ip ERR: Network node 
err ", e);
+                       }
+               }
+       }
+
+       private static void parseIPv6Whitelist(final JSONObject config, final 
AnonymousIp anonymousIp) throws JSONException {
+               if (config.optJSONArray("ip6Whitelist") != null) {
+                       try {
+                               anonymousIp.ipv6Whitelist = new 
AnonymousIpWhitelist();
+                               
anonymousIp.ipv6Whitelist.init(config.optJSONArray("ip6Whitelist"));
+                       } catch (NetworkNodeException e) {
+                               LOGGER.error("Anonymous Ip ERR: Network node 
err ", e);
+                       }
+               }
+       }
+
+       @SuppressWarnings({ "PMD.NPathComplexity", "PMD.CyclomaticComplexity" })
+       private static AnonymousIp parseConfigJson(final JSONObject config) {
+               final AnonymousIp anonymousIp = new AnonymousIp();
+               try {
+                       final JSONObject blockingTypes = 
config.getJSONObject("anonymousIp");
+
+                       anonymousIp.blockAnonymousIp = 
blockingTypes.getBoolean("blockAnonymousVPN");
+                       anonymousIp.blockHostingProvider = 
blockingTypes.getBoolean("blockHostingProvider");
+                       anonymousIp.blockPublicProxy = 
blockingTypes.getBoolean("blockPublicProxy");
+                       anonymousIp.blockTorExitNode = 
blockingTypes.getBoolean("blockTorExitNode");
+
+                       anonymousIp.enabled = AnonymousIp.currentConfig.enabled;
+
+                       parseIPv4Whitelist(config, anonymousIp);
+                       parseIPv6Whitelist(config, anonymousIp);
+
+                       return anonymousIp;
+               } catch (Exception e) {
+                       LOGGER.error("AnonymousIp ERR: parsing config file 
failed", e);
+               }
+
+               return null;
+       }
+
+       @SuppressWarnings({ "PMD.NPathComplexity" })
+       public static boolean parseConfigFile(final File f, final boolean 
verifyOnly) {
+               JSONObject json = null;
+               try {
+                       json = new JSONObject(new JSONTokener(new 
FileReader(f)));
+               } catch (Exception e) {
+                       LOGGER.error("AnonymousIp ERR: json file exception " + 
f, e);
+                       return false;
+               }
+
+               final AnonymousIp anonymousIp = parseConfigJson(json);
+
+               if (anonymousIp == null) {
+                       return false;
+               }
+
+               if (!verifyOnly) {
+                       currentConfig = anonymousIp; // point to the new parsed 
object
+               }
+
+               return true;
+       }
+
+       private static boolean inWhitelist(final String address) {
+               // If the address is ipv4 check against the ipv4whitelist
+               if (address.indexOf(':') == -1) {
+                       if (currentConfig.ipv4Whitelist.contains(address)) {
+                               return true;
+                       }
+               }
+
+               // If the address is ipv6 check against the ipv6whitelist
+               else {
+                       if (currentConfig.ipv6Whitelist.contains(address)) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
+       public static boolean enforce(final TrafficRouter trafficRouter, final 
String dsvcId, final String url, final String ip) {
+
+               final InetAddress address = InetAddresses.forString(ip);
+
+               if (inWhitelist(ip)) {
+                       return false;
+               }
+
+               final AnonymousIpResponse response = 
trafficRouter.getAnonymousIpDatabaseService().lookupIp(address);
+
+               if (response == null) {
+                       return false;
+               }
+
+               // Check if the ip should be blocked by checking if the ip 
falls into a
+               // specific policy
+               if (AnonymousIp.getCurrentConfig().blockAnonymousIp && 
response.isAnonymousVpn()) {
+                       return true;
+               }
+
+               if (AnonymousIp.getCurrentConfig().blockHostingProvider && 
response.isHostingProvider()) {
+                       return true;
+               }
+
+               if (AnonymousIp.getCurrentConfig().blockPublicProxy && 
response.isPublicProxy()) {
+                       return true;
+               }
+
+               if (AnonymousIp.getCurrentConfig().blockTorExitNode && 
response.isTorExitNode()) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       @SuppressWarnings({ "PMD.CyclomaticComplexity" })
+       /*
+        * Enforces the anonymous ip blocking policies
+        * 
+        * If the Delivery Service has anonymous ip blocking enabled And the ip 
is
+        * in the anonymous ip database The ip will be blocked if it matches a
+        * policy defined in the config file
+        */
+       public static void enforce(final TrafficRouter trafficRouter, final 
Request request, final DeliveryService deliveryService, final Cache cache,
+                       final HTTPRouteResult routeResult, final Track track) 
throws MalformedURLException {
+
+               final HTTPRequest httpRequest = HTTPRequest.class.cast(request);
+
+               // If the database isn't initialized dont block
+               if 
(!trafficRouter.getAnonymousIpDatabaseService().isInitialized()) {
+                       return;
+               }
+
+               // Check if the ip is allowed
+               final boolean block = enforce(trafficRouter, 
deliveryService.getId(), httpRequest.getRequestedUrl(), 
httpRequest.getClientIP());
+
+               // Block the ip if it is not allowed
+               if (block) {
+                       routeResult.setResponseCode(AnonymousIp.BLOCK_CODE);
+                       track.setResult(ResultType.ANON_BLOCK);
+               }
+       }
+}
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpConfigUpdater.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpConfigUpdater.java
new file mode 100644
index 0000000..324bb32
--- /dev/null
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpConfigUpdater.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Cisco Systems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+public class AnonymousIpConfigUpdater extends AbstractServiceUpdater {
+    private static final Logger LOGGER = 
Logger.getLogger(AnonymousIpConfigUpdater.class);
+
+    public AnonymousIpConfigUpdater() {
+        LOGGER.debug("init...");
+        sourceCompressed = false;
+        tmpPrefix = "anonymousip";
+        tmpSuffix = ".json";
+    }
+    
+    @Override
+    /*
+     * Loads the anonymous ip config file
+     */
+    public boolean loadDatabase() throws IOException {
+       LOGGER.debug("AnonymousIpConfigUodater loading config");
+        final File existingDB = 
databasesDirectory.resolve(databaseName).toFile();
+        return AnonymousIp.parseConfigFile(existingDB, false);
+    }
+
+    @Override
+    /*
+     * Verifies the anonymous ip config file
+     */
+    public boolean verifyDatabase(final File dbFile) throws IOException {
+       LOGGER.debug("AnonymousIpConfigUpdater verifying config");
+        return AnonymousIp.parseConfigFile(dbFile, true);
+    }
+
+}
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseService.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseService.java
new file mode 100644
index 0000000..7fe368a
--- /dev/null
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseService.java
@@ -0,0 +1,117 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+
+import org.apache.log4j.Logger;
+
+import com.maxmind.geoip2.DatabaseReader;
+import com.maxmind.geoip2.exception.GeoIp2Exception;
+import com.maxmind.geoip2.model.AnonymousIpResponse;
+
+@SuppressWarnings({ "PMD.AvoidDuplicateLiterals" })
+public class AnonymousIpDatabaseService {
+       private static final Logger LOGGER = 
Logger.getLogger(AnonymousIpDatabaseService.class);
+
+       private boolean initialized = false;
+       private File databaseFile;
+       private DatabaseReader databaseReader;
+
+       /*
+        * Reloads the anonymous ip database
+        */
+       public void reloadDatabase() throws IOException {
+               if (databaseReader != null) {
+                       databaseReader.close();
+               }
+
+               if (databaseFile != null) {
+                       final DatabaseReader reader = 
createDatabaseReader(databaseFile);
+                       if (reader != null) {
+                               databaseReader = reader;
+                               initialized = true;
+                       } else {
+                               throw new IOException("Could not create 
database reader");
+                       }
+               }
+       }
+
+       public void setDatabaseFile(final File databaseFile) {
+               this.databaseFile = databaseFile;
+       }
+
+       /*
+        * Verifies the database by attempting to recreate it
+        */
+       public boolean verifyDatabase(final File databaseFile) throws 
IOException {
+               return createDatabaseReader(databaseFile) != null;
+       }
+
+       /*
+        * Creates a DatabaseReader object using an input database file
+        */
+       private DatabaseReader createDatabaseReader(final File databaseFile) 
throws IOException {
+               if (!databaseFile.exists()) {
+                       LOGGER.warn(databaseFile.getAbsolutePath() + " does not 
exist yet!");
+                       return null;
+               }
+
+               if (databaseFile.isDirectory()) {
+                       LOGGER.error(databaseFile + " is a directory, need a 
file");
+                       return null;
+               }
+
+               LOGGER.info("Loading Anonymous IP db: " + 
databaseFile.getAbsolutePath());
+
+               try {
+                       final DatabaseReader reader = new 
DatabaseReader.Builder(databaseFile).build();
+                       return reader;
+               } catch (Exception e) {
+                       LOGGER.error(databaseFile.getAbsolutePath() + " is not 
a valid Anonymous IP data file", e);
+                       return null;
+               }
+       }
+
+       /*
+        * Returns an AnonymousIpResponse from looking an ip up in the database
+        */
+       public AnonymousIpResponse lookupIp(final InetAddress ipAddress) {
+               if (initialized) {
+                       // Return an anonymousIp object after looking up the ip 
in the
+                       // database
+                       try {
+                               return databaseReader.anonymousIp(ipAddress);
+                       } catch (GeoIp2Exception e) {
+                               LOGGER.debug(String.format("AnonymousIP: IP %s 
not found in anonymous ip database", ipAddress.getHostAddress()));
+                               return null;
+                       } catch (IOException e) {
+                               LOGGER.error("AnonymousIp ERR: IO Error during 
lookup of ip in anonymous ip database", e);
+                               return null;
+                       }
+               } else {
+                       return null;
+               }
+       }
+
+       public boolean isInitialized() {
+               return initialized;
+       }
+
+       /*
+        * Closes the database when the object is destroyed
+        */
+       @Override
+       protected void finalize() throws Throwable {
+               if (databaseReader != null) {
+                       try {
+                               databaseReader.close();
+                               databaseReader = null;
+                       } catch (IOException e) {
+                               LOGGER.warn("Caught exception while trying to 
close anonymous ip database reader: ", e);
+                       }
+               }
+               super.finalize();
+       }
+
+}
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseUpdater.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseUpdater.java
new file mode 100644
index 0000000..17aa623
--- /dev/null
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseUpdater.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Cisco Systems, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+@SuppressWarnings({ "PMD.AvoidDuplicateLiterals" })
+public class AnonymousIpDatabaseUpdater extends AbstractServiceUpdater {
+    private static final Logger LOGGER = 
Logger.getLogger(AnonymousIpDatabaseUpdater.class);
+
+       private AnonymousIpDatabaseService anonymousIpDatabaseService;
+
+       @Override
+       /*
+        * Verifies the anonymous ip database
+        */
+       public boolean verifyDatabase(final File dbFile) throws IOException {
+               LOGGER.debug("Verifying Anonymous IP Database");
+               return anonymousIpDatabaseService.verifyDatabase(dbFile);
+       }
+
+       /*
+        * Sets the anonymous ip database file and reloads the database
+        */
+       public boolean loadDatabase() throws IOException {
+               LOGGER.debug("Loading Anonymous IP Database");
+               
anonymousIpDatabaseService.setDatabaseFile(databasesDirectory.resolve(databaseName).toFile());
+               anonymousIpDatabaseService.reloadDatabase();
+               return true;
+       }
+
+       @Override
+       /*
+        * Returns a boolean with the initialization state of the database
+        */
+       public boolean isLoaded() {
+               if (anonymousIpDatabaseService != null) {
+                       return anonymousIpDatabaseService.isInitialized();
+               }
+
+               return loaded;
+       }
+       
+       public void setAnonymousIpDatabaseService(final 
AnonymousIpDatabaseService anonymousIpDatabaseService) {
+               this.anonymousIpDatabaseService = anonymousIpDatabaseService;
+       }
+
+}
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelist.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelist.java
new file mode 100644
index 0000000..d8bc3fc
--- /dev/null
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelist.java
@@ -0,0 +1,48 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import org.apache.log4j.Logger;
+import org.apache.wicket.ajax.json.JSONArray;
+import org.apache.wicket.ajax.json.JSONException;
+
+public class AnonymousIpWhitelist {
+       private static final Logger LOGGER = 
Logger.getLogger(AnonymousIpWhitelist.class);
+
+       final private NetworkNode.SuperNode whitelist;
+
+       public AnonymousIpWhitelist() throws NetworkNodeException {
+               whitelist = new NetworkNode.SuperNode();
+       }
+
+       public void init(final JSONArray config) throws JSONException, 
NetworkNodeException {
+               for (int i = 0; i < config.length(); i++) {
+                       final String network = config.getString(i);
+                       this.add(network);
+               }
+       }
+
+       public void add(final String network) throws NetworkNodeException {
+               final NetworkNode node = new NetworkNode(network, 
AnonymousIp.WHITE_LIST_LOC);
+               if (network.indexOf(':') == -1) {
+                       whitelist.add(node);
+               } else {
+                       whitelist.add6(node);
+               }
+       }
+
+       public boolean contains(final String address) {
+               if (whitelist == null) {
+                       return false;
+               }
+
+               try {
+                       final NetworkNode nn = whitelist.getNetwork(address);
+                       if (nn.getLoc() == AnonymousIp.WHITE_LIST_LOC) {
+                               return true;
+                       }
+               } catch (NetworkNodeException e) {
+                       LOGGER.warn("AnonymousIp: exception", e);
+               }
+
+               return false;
+       }
+}
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/StatTracker.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/StatTracker.java
index b444cd8..ccc675c 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/StatTracker.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/StatTracker.java
@@ -111,7 +111,7 @@ public class StatTracker {
                }
 
                public static enum ResultType {
-                       ERROR, CZ, GEO, MISS, STATIC_ROUTE, DS_REDIRECT, 
DS_MISS, INIT, FED, RGDENY, RGALT, GEO_REDIRECT, DEEP_CZ
+                       ERROR, CZ, GEO, MISS, STATIC_ROUTE, DS_REDIRECT, 
DS_MISS, INIT, FED, RGDENY, RGALT, GEO_REDIRECT, DEEP_CZ, ANON_BLOCK
                }
 
                public enum ResultDetails {
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
index 9662fd8..43a94ad 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
@@ -67,6 +67,8 @@ import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Tr
 import 
com.comcast.cdn.traffic_control.traffic_router.core.util.TrafficOpsUtils;
 import com.comcast.cdn.traffic_control.traffic_router.core.util.CidrAddress;
 import 
com.comcast.cdn.traffic_control.traffic_router.core.router.StatTracker.Track.ResultDetails;
+import com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIp;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpDatabaseService;
 
 public class TrafficRouter {
        public static final Logger LOGGER = 
Logger.getLogger(TrafficRouter.class);
@@ -76,6 +78,7 @@ public class TrafficRouter {
        private final ZoneManager zoneManager;
        private final GeolocationService geolocationService;
        private final GeolocationService geolocationService6;
+       private final AnonymousIpDatabaseService anonymousIpService;
        private final FederationRegistry federationRegistry;
        private final boolean consistentDNSRouting;
 
@@ -91,7 +94,8 @@ public class TrafficRouter {
 
        public TrafficRouter(final CacheRegister cr, 
                        final GeolocationService geolocationService, 
-                       final GeolocationService geolocationService6, 
+                       final GeolocationService geolocationService6,
+                       final AnonymousIpDatabaseService anonymousIpService,
                        final StatTracker statTracker,
                        final TrafficOpsUtils trafficOpsUtils,
                        final FederationRegistry federationRegistry,
@@ -99,6 +103,7 @@ public class TrafficRouter {
                this.cacheRegister = cr;
                this.geolocationService = geolocationService;
                this.geolocationService6 = geolocationService6;
+               this.anonymousIpService = anonymousIpService;
                this.federationRegistry = federationRegistry;
                this.consistentDNSRouting = 
JsonUtils.optBoolean(cr.getConfig(), "consistent.dns.routing");
                this.zoneManager = new ZoneManager(this, statTracker, 
trafficOpsUtils, trafficRouterManager);
@@ -199,6 +204,10 @@ public class TrafficRouter {
                return geolocationService;
        }
 
+       public AnonymousIpDatabaseService getAnonymousIpDatabaseService() {
+               return anonymousIpService;
+       }
+
        public Geolocation getLocation(final String clientIP) throws 
GeolocationException {
                return clientIP.contains(":") ? 
geolocationService6.location(clientIP) : geolocationService.location(clientIP);
        }
@@ -532,6 +541,7 @@ public class TrafficRouter {
                return routeResult;
        }
 
+       @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
        public HTTPRouteResult route(final HTTPRequest request, final Track 
track) throws MalformedURLException, GeolocationException {
                track.setRouteType(RouteType.HTTP, request.getHostname());
 
@@ -574,6 +584,16 @@ public class TrafficRouter {
 
                final Cache cache = consistentHasher.selectHashable(caches, 
deliveryService.getDispersion(), request.getPath());
 
+               // Enforce anonymous IP blocking if a DS has anonymous blocking 
enabled
+               // and the feature is enabled
+               if (deliveryService.isAnonymousIpEnabled() && 
AnonymousIp.getCurrentConfig().enabled) {
+                       AnonymousIp.enforce(this, request, deliveryService, 
cache, routeResult, track);
+
+                       if (routeResult.getResponseCode() == 
AnonymousIp.BLOCK_CODE) {
+                               return routeResult;
+                       }
+               }
+
                if (deliveryService.isRegionalGeoEnabled()) {
                        RegionalGeo.enforce(this, request, deliveryService, 
cache, routeResult, track);
                        return routeResult;
diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouterManager.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouterManager.java
index 26b20c2..941ba51 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouterManager.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouterManager.java
@@ -32,6 +32,7 @@ import 
com.comcast.cdn.traffic_control.traffic_router.core.util.TrafficOpsUtils;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpDatabaseService;
 
 public class TrafficRouterManager implements 
ApplicationListener<ContextRefreshedEvent> {
        private static final Logger LOGGER = 
Logger.getLogger(TrafficRouterManager.class);
@@ -42,6 +43,7 @@ public class TrafficRouterManager implements 
ApplicationListener<ContextRefreshe
        private TrafficRouter trafficRouter;
        private GeolocationService geolocationService;
        private GeolocationService geolocationService6;
+       private AnonymousIpDatabaseService anonymousIpService;
        private StatTracker statTracker;
        private static final Map<String, Long> timeTracker = new 
ConcurrentHashMap<String, Long>();
        private NameServer nameServer;
@@ -98,7 +100,7 @@ public class TrafficRouterManager implements 
ApplicationListener<ContextRefreshe
                        return;
                }
 
-               final TrafficRouter tr = new TrafficRouter(cacheRegister, 
geolocationService, geolocationService6, statTracker, trafficOpsUtils, 
federationRegistry, this);
+               final TrafficRouter tr = new TrafficRouter(cacheRegister, 
geolocationService, geolocationService6, anonymousIpService, statTracker, 
trafficOpsUtils, federationRegistry, this);
                tr.setSteeringRegistry(steeringRegistry);
                synchronized(this) {
                        if (state != null) {
@@ -126,6 +128,10 @@ public class TrafficRouterManager implements 
ApplicationListener<ContextRefreshe
                this.geolocationService6 = geolocationService;
        }
 
+       public void setAnonymousIpService(final AnonymousIpDatabaseService 
anonymousIpService) {
+               this.anonymousIpService = anonymousIpService;
+       }
+
        public void setStatTracker(final StatTracker statTracker) {
                this.statTracker = statTracker;
        }
diff --git a/traffic_router/core/src/main/webapp/WEB-INF/applicationContext.xml 
b/traffic_router/core/src/main/webapp/WEB-INF/applicationContext.xml
index fb5cca3..a46fdf7 100644
--- a/traffic_router/core/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/traffic_router/core/src/main/webapp/WEB-INF/applicationContext.xml
@@ -62,6 +62,7 @@
                <property name="federationRegistry" ref="federationsRegistry" />
                <property name="geolocationService" 
ref="maxmindGeolocationService" />
                <property name="geolocationService6" 
ref="maxmindGeolocationService" />
+               <property name="anonymousIpService" 
ref="anonymousIpDatabaseService" />
                <property name="steeringRegistry" ref="steeringRegistry" />
        </bean>
 
@@ -111,6 +112,8 @@
                <property name="networkUpdater" ref="networkUpdater" />
                <property name="deepNetworkUpdater" ref="deepNetworkUpdater" />
                <property name="regionalGeoUpdater" ref="regionalGeoUpdater" />
+               <property name="anonymousIpConfigUpdater" 
ref="anonymousIpConfigUpdater" />
+               <property name="anonymousIpDatabaseUpdater" 
ref="anonymousIpDatabaseUpdater" />
                <property name="statTracker" ref="statTracker" />
                <property name="configDir" value="/opt/traffic_router/conf" />
                <property name="federationsWatcher" ref="federationsWatcher" />
@@ -127,6 +130,7 @@
        </bean>
 
        <bean id="maxmindGeolocationService" 
class="com.comcast.cdn.traffic_control.traffic_router.core.loc.MaxmindGeolocationService"/>
+       <bean id="anonymousIpDatabaseService" 
class="com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpDatabaseService"/>
        
        <bean id="geolocationDatabaseUpdater" 
class="com.comcast.cdn.traffic_control.traffic_router.core.loc.GeolocationDatabaseUpdater"
 init-method="init">
                <property name="databasesDirectory" ref="databasesDir"/>
@@ -162,6 +166,25 @@
                <property name="trafficRouterManager" 
ref="trafficRouterManager" />
        </bean>
 
+       <bean id="anonymousIpConfigUpdater" 
class="com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpConfigUpdater"
+               init-method="init">
+               <property name="executorService" ref="ScheduledExecutorService" 
/>
+               <property name="databasesDirectory" ref="databasesDir" />
+               <property name="databaseName" 
value="$[cache.anonymousip.database:anonymous_ip.json]" />
+               <property name="pollingInterval" 
value="$[cache.anonymousip.database.refresh.period:10800000]" />
+               <property name="trafficRouterManager" 
ref="trafficRouterManager" />
+       </bean>
+
+       <bean id="anonymousIpDatabaseUpdater" 
class="com.comcast.cdn.traffic_control.traffic_router.core.loc.AnonymousIpDatabaseUpdater"
+               init-method="init">
+               <property name="executorService" ref="ScheduledExecutorService" 
/>
+               <property name="databasesDirectory" ref="databasesDir" />
+               <property name="databaseName" 
value="$[cache.anonymousip.database:GeoIP2-Anonymous-IP.mmdb]" />
+               <property name="pollingInterval" 
value="$[cache.anonymousip.database.refresh.period:10800000]" />
+               <property name="trafficRouterManager" 
ref="trafficRouterManager" />
+               <property name="anonymousIpDatabaseService" 
ref="anonymousIpDatabaseService" />
+       </bean>
+
        <bean id="ScheduledExecutorService" 
class="java.util.concurrent.Executors"
                factory-method="newSingleThreadScheduledExecutor" />
 
diff --git 
a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseServiceTest.java
 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseServiceTest.java
new file mode 100644
index 0000000..1333894
--- /dev/null
+++ 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseServiceTest.java
@@ -0,0 +1,81 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.maxmind.geoip2.exception.GeoIp2Exception;
+
+public class AnonymousIpDatabaseServiceTest {
+
+       private AnonymousIpDatabaseService anonymousIpService;
+       private final static String mmdb = 
"src/test/resources/GeoIP2-Anonymous-IP.mmdb";
+
+       @Before
+       public void setup() throws Exception {
+               // ignore the test if there is no mmdb file
+               File mmdbFile = new File(mmdb);
+               org.junit.Assume.assumeTrue(mmdbFile.exists());
+
+               anonymousIpService = new AnonymousIpDatabaseService();
+               File databaseFile = new File(mmdb);
+               anonymousIpService.setDatabaseFile(databaseFile);
+               anonymousIpService.reloadDatabase();
+               assert anonymousIpService.isInitialized();
+       }
+
+       @Test
+       public void testIpInDatabase() throws Exception {
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("223.26.48.248")), 
notNullValue());
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("223.26.48.248")), 
notNullValue());
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("1.1.205.152")), 
notNullValue());
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("18.85.22.204")), 
notNullValue());
+       }
+
+       @Test
+       public void testIpNotInDatabase() throws Exception {
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("192.168.0.1")), 
equalTo(null));
+       }
+
+       @Test
+       public void testDatabaseNotLoaded() throws UnknownHostException, 
IOException, GeoIp2Exception {
+               AnonymousIpDatabaseService anonymousIpService = new 
AnonymousIpDatabaseService();
+               assertThat(anonymousIpService.isInitialized(), equalTo(false));
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("223.26.48.248")), 
equalTo(null));
+               
assertThat(anonymousIpService.lookupIp(InetAddress.getByName("192.168.0.1")), 
equalTo(null));
+       }
+
+       @Test
+       public void testLookupTime() throws IOException {
+               final InetAddress ipAddress = 
InetAddress.getByName("223.26.48.248");
+               final long start = System.nanoTime();
+
+               long total = 100000;
+
+               for (int i = 0; i <= total; i++) {
+                       anonymousIpService.lookupIp(ipAddress);
+               }
+
+               long duration = System.nanoTime() - start;
+               
+               System.out.println(String.format("Anonymous IP database average 
lookup: %s nanoseconds", Long.toString(duration / total)));
+       }
+
+       @After
+       public void tearDown() throws Exception {
+               try {
+                       anonymousIpService.finalize();
+               } catch (Throwable e) {
+               }
+       }
+
+}
diff --git 
a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpTest.java
 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpTest.java
new file mode 100644
index 0000000..271c62d
--- /dev/null
+++ 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpTest.java
@@ -0,0 +1,258 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.TrafficRouter;
+
+public class AnonymousIpTest {
+       private TrafficRouter trafficRouter;
+
+       final File configFile = new 
File("src/test/resources/anonymous_ip.json");
+       final File configNoWhitelist = new 
File("src/test/resources/anonymous_ip_no_whitelist.json");
+
+       final String mmdb = "src/test/resources/GeoIP2-Anonymous-IP.mmdb";
+       File databaseFile = new File(mmdb);
+
+       @Before
+       public void setUp() throws Exception {
+               // ignore the test if there is no mmdb file
+               File mmdbFile = new File(mmdb);
+               org.junit.Assume.assumeTrue(mmdbFile.exists());
+
+               AnonymousIp.parseConfigFile(configFile, false);
+               assert (AnonymousIp.getCurrentConfig().getIPv4Whitelist() != 
null);
+               assert (AnonymousIp.getCurrentConfig().getIPv6Whitelist() != 
null);
+
+               // Set up a mock traffic router with real database
+               AnonymousIpDatabaseService anonymousIpService = new 
AnonymousIpDatabaseService();
+               anonymousIpService.setDatabaseFile(databaseFile);
+               anonymousIpService.reloadDatabase();
+               assert anonymousIpService.isInitialized();
+               trafficRouter = mock(TrafficRouter.class);
+               
when(trafficRouter.getAnonymousIpDatabaseService()).thenReturn(anonymousIpService);
+               assert (trafficRouter.getAnonymousIpDatabaseService() != null);
+       }
+
+       @Test
+       public void testConfigFileParsingIpv4() {
+               AnonymousIp currentConfig = AnonymousIp.getCurrentConfig();
+               assertThat(currentConfig, notNullValue());
+               AnonymousIpWhitelist whitelist = 
currentConfig.getIPv4Whitelist();
+               assertThat(whitelist, notNullValue());
+       }
+
+       @Test
+       public void testConfigFileParsingIpv6() {
+               AnonymousIp currentConfig = AnonymousIp.getCurrentConfig();
+               assertThat(currentConfig, notNullValue());
+               AnonymousIpWhitelist whitelist = 
currentConfig.getIPv6Whitelist();
+               assertThat(whitelist, notNullValue());
+       }
+
+       @Test
+       public void testIpInWhitelistIsAllowed() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "5.34.32.79";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testFallsUnderManyPolicies() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2.38.158.142";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(true));
+       }
+
+       @Test
+       public void testAllowNotCheckingPolicy() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2.36.248.52";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testEnforceAllowed() throws IOException {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "10.0.0.1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testEnforceAllowedIpInWhitelist() throws IOException {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "10.0.2.1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testEnforceBlocked() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "223.26.48.248";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(true));
+       }
+
+       @Test
+       public void testEnforceNotInWhitelistNotInDB() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "192.168.0.1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+
+               assertThat(result, equalTo(false));
+       }
+
+       /* IPv4 no whitelist */
+
+       @Test
+       public void testEnforceNoWhitelistAllowed() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "192.168.0.1";
+               AnonymousIp.parseConfigFile(configNoWhitelist, false);
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testEnforceNoWhitelistBlocked() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "223.26.48.248";
+               AnonymousIp.parseConfigFile(configNoWhitelist, false);
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(true));
+       }
+
+       @Test
+       public void testEnforceNoWhitelistNotEnforcePolicy() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2.36.248.52";
+               AnonymousIp.parseConfigFile(configNoWhitelist, false);
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       /* IPv6 Testing */
+
+       @Test
+       public void testIpv6EnforceBlock() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2001:418:9807::1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(true));
+       }
+
+       @Test
+       public void testIpv6EnforceNotBlock() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2001:418::1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testIpv6EnforceNotBlockWhitelisted() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2001:550:90a:0:0:0:0:1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testIpv6EnforceNotBlockOnWhitelist() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "::1";
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       /* IPv6 tests no whitelist */
+
+       @Test
+       public void testIpv6NoWhitelistEnforceBlock() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2001:418:9807::1";
+               AnonymousIp.parseConfigFile(configNoWhitelist, false);
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(true));
+       }
+
+       @Test
+       public void testIpv6NoWhitelistNoBlock() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "::1";
+               AnonymousIp.parseConfigFile(configNoWhitelist, false);
+
+               final boolean result = AnonymousIp.enforce(trafficRouter, 
dsvcId, url, ip);
+               assertThat(result, equalTo(false));
+       }
+
+       @Test
+       public void testAnonymousIpPerformance() {
+               final String dsvcId = "dsID";
+               final String url = "http://ds1.example.com/live1";;
+               final String ip = "2.36.248.52";
+
+               long total = 100000;
+
+               long start = System.nanoTime();
+
+               for (int i = 0; i <= total; i++) {
+                       final boolean result = 
AnonymousIp.enforce(trafficRouter, dsvcId, url, ip);
+               }
+
+               long duration = System.nanoTime() - start;
+
+               System.out.println(String.format("Anonymous IP blocking average 
took %s nanoseconds", Long.toString(duration / total)));
+       }
+}
diff --git 
a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelistTest.java
 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelistTest.java
new file mode 100644
index 0000000..1dfe57c
--- /dev/null
+++ 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelistTest.java
@@ -0,0 +1,227 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.loc;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.wicket.ajax.json.JSONArray;
+import org.apache.wicket.ajax.json.JSONException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnonymousIpWhitelistTest {
+
+       AnonymousIpWhitelist ip4whitelist;
+       AnonymousIpWhitelist ip6whitelist;
+
+       @Before
+       public void setup() throws JSONException, NetworkNodeException {
+               ip4whitelist = new AnonymousIpWhitelist();
+               ip4whitelist.init(new JSONArray("[\"192.168.30.0/24\", 
\"10.0.2.0/24\", \"10.0.0.0/16\"]"));
+
+               ip6whitelist = new AnonymousIpWhitelist();
+               ip6whitelist.init(new JSONArray("[\"::1/32\", \"2001::/64\"]"));
+       }
+
+       @Test
+       public void testAnonymousIpWhitelistConstructor() {
+               // final InetAddress address = 
InetAddresses.forString("192.168.30.1");
+               assertThat(ip4whitelist.contains("192.168.30.1"), 
equalTo(true));
+       }
+
+       @Test
+       public void testIPsInWhitelist() {
+               assertThat(ip4whitelist.contains("192.168.30.1"), 
equalTo(true));
+
+               assertThat(ip4whitelist.contains("192.168.30.254"), 
equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.2.1"), equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.2.254"), equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.1.1"), equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.254.254"), 
equalTo(true));
+       }
+
+       @Test
+       public void testIPsNotInWhitelist() {
+               assertThat(ip4whitelist.contains("192.168.31.1"), 
equalTo(false));
+
+               assertThat(ip4whitelist.contains("192.167.30.1"), 
equalTo(false));
+
+               assertThat(ip4whitelist.contains("10.1.1.1"), equalTo(false));
+
+               assertThat(ip4whitelist.contains("10.10.1.1"), equalTo(false));
+       }
+
+       /* IPv6 Testing */
+
+       @Test
+       public void testIPv6AddressInWhitelist() {
+               assertThat(ip6whitelist.contains("::1"), equalTo(true));
+       }
+
+       @Test
+       public void testIPv6AddressInWhitelistInSubnet() {
+               assertThat(ip6whitelist.contains("2001::"), equalTo(true));
+
+               assertThat(ip6whitelist.contains("2001:0:0:0:0:0:0:1"), 
equalTo(true));
+
+               assertThat(ip6whitelist.contains("2001:0:0:0:0:0:1:1"), 
equalTo(true));
+
+               assertThat(ip6whitelist.contains("2001:0:0:0:a:a:a:a"), 
equalTo(true));
+
+               
assertThat(ip6whitelist.contains("2001:0:0:0:ffff:ffff:ffff:ffff"), 
equalTo(true));
+       }
+
+       @Test
+       public void testIpv6AddressNotInWhitelist() {
+               assertThat(ip6whitelist.contains("2001:1:0:0:0:0:0:0"), 
equalTo(false));
+
+               assertThat(ip6whitelist.contains("2001:0:1::"), equalTo(false));
+
+               assertThat(ip6whitelist.contains("2002:0:0:0:0:0:0:1"), 
equalTo(false));
+
+               
assertThat(ip6whitelist.contains("2001:0:0:1:ffff:ffff:ffff:ffff"), 
equalTo(false));
+       }
+
+       @Test
+       public void testWhitelistCreationLeafFirst() throws JSONException, 
NetworkNodeException {
+               ip4whitelist.init(new JSONArray("[\"10.0.2.0/24\", 
\"10.0.0.0/16\"]"));
+
+               assertThat(ip4whitelist.contains("10.0.2.1"), equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.10.1"), equalTo(true));
+       }
+
+       @Test
+       public void testWhitelistCreationParentFirst() throws JSONException, 
NetworkNodeException {
+               ip4whitelist.init(new JSONArray("[\"10.0.0.0/16\"], 
\"10.0.2.0/24\""));
+
+               assertThat(ip4whitelist.contains("10.0.2.1"), equalTo(true));
+
+               assertThat(ip4whitelist.contains("10.0.10.1"), equalTo(true));
+       }
+
+       /* IPv4 validation */
+
+       @Test(expected = JSONException.class)
+       public void badIPv4Input1() throws JSONException, NetworkNodeException {
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"192.168.1/24\"]"));
+               assertThat(badlist.contains("192.168.0.1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void badIPv4Input2() throws JSONException, NetworkNodeException {
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"256.168.0.1/24\"]"));
+               assertThat(badlist.contains("192.168.0.1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void badNetmaskInput1() throws JSONException, 
NetworkNodeException {
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"192.168.0.1/33\"]"));
+               assertThat(badlist.contains("192.168.0.1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void badNetmaskInput2() throws JSONException, 
NetworkNodeException {
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"::1/129\"]"));
+               assertThat(badlist.contains("::1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void badNetmaskInput3() throws JSONException, 
NetworkNodeException {
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"192.168.0.1/-1\"]"));
+               assertThat(badlist.contains("192.168.0.1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void validIPv4Input() throws JSONException, NetworkNodeException 
{
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"192.168.0.1/32\"]"));
+               assertThat(badlist.contains("192.168.0.1"), equalTo(false));
+       }
+
+       @Test(expected = JSONException.class)
+       public void validIPv6Input() throws JSONException, NetworkNodeException 
{
+               AnonymousIpWhitelist badlist = new AnonymousIpWhitelist();
+               badlist.init(new JSONArray("[\"\"::1/128\"]"));
+               assertThat(badlist.contains("::1"), equalTo(false));
+       }
+
+       /* NetworkNode takes forever to create Tree - commented out until it is 
needed
+       @Test
+       public void testAnonymousIpWhitelistPerformance65000() throws 
NetworkNodeException {
+               AnonymousIpWhitelist whitelist = new AnonymousIpWhitelist();
+               List<String> tempList = new ArrayList<>();
+               // add a bunch of ips to the whitelist
+
+               for (int i = 0; i < 255; i++) {
+                       for (int j = 0; j < 255; j++) {
+                               int a = ThreadLocalRandom.current().nextInt(1, 
254 + 1);
+                               int b = ThreadLocalRandom.current().nextInt(1, 
254 + 1);
+                               int c = ThreadLocalRandom.current().nextInt(1, 
254 + 1);
+                               int d = ThreadLocalRandom.current().nextInt(1, 
254 + 1);
+                               tempList.add(String.format("%s.%s.%s.%s", a, b, 
c, d));
+                       }
+               }
+
+               long startTime = System.nanoTime();
+
+               for (int i = 0; i < tempList.size(); i++) {
+                       whitelist.add(tempList.get(i) + "/32");
+               }
+
+               long durationTime = System.nanoTime() - startTime;
+
+               System.out.println(String.format("Anonymous IP Whitelist 
creation took %s nanoseconds to create tree of %d subnets", 
Long.toString(durationTime),
+                               tempList.size()));
+
+               int total = 1000;
+
+               long start = System.nanoTime();
+
+               for (int i = 0; i <= total; i++) {
+                       whitelist.contains("192.168.30.1");
+               }
+
+               long duration = System.nanoTime() - start;
+
+               System.out.println(
+                               String.format("Anonymous IP Whitelist average 
lookup took %s nanoseconds for %d ips", Long.toString(duration / total), 
tempList.size()));
+       }
+       */
+       @Test
+       public void testAddSubnets() throws NetworkNodeException {
+               AnonymousIpWhitelist whitelist = new AnonymousIpWhitelist();
+
+               whitelist.add("192.168.1.1/32");
+               assertThat(whitelist.contains("192.168.1.1"), equalTo(true));
+
+               whitelist.add("192.168.1.0/24");
+               assertThat(whitelist.contains("192.168.1.255"), equalTo(true));
+               assertThat(whitelist.contains("192.168.1.167"), equalTo(true));
+
+               whitelist.add("192.168.1.0/27");
+               assertThat(whitelist.contains("192.168.1.255"), equalTo(true));
+               assertThat(whitelist.contains("192.168.1.167"), equalTo(true));
+
+               whitelist.add("10.0.0.1/32");
+               assertThat(whitelist.contains("10.0.0.1"), equalTo(true));
+               assertThat(whitelist.contains("10.0.0.2"), equalTo(false));
+               assertThat(whitelist.contains("192.168.2.1"), equalTo(false));
+               assertThat(whitelist.contains("192.168.2.255"), equalTo(false));
+               assertThat(whitelist.contains("192.167.1.1"), equalTo(false));
+               assertThat(whitelist.contains("192.169.1.1"), equalTo(false));
+               assertThat(whitelist.contains("10.0.0.0"), equalTo(false));
+       }
+}
diff --git a/traffic_router/core/src/test/resources/anonymous_ip.json 
b/traffic_router/core/src/test/resources/anonymous_ip.json
new file mode 100644
index 0000000..e64d0a5
--- /dev/null
+++ b/traffic_router/core/src/test/resources/anonymous_ip.json
@@ -0,0 +1,16 @@
+{
+
+   "customer": "Cisco",
+   "version": "1",
+   "date" : "2017-05-23 03:28:25",
+   "name": "Anonymous IP Blocking Policy",
+
+   "anonymousIp": { "blockAnonymousVPN": true,
+                    "blockHostingProvider": true, 
+                    "blockPublicProxy": true,
+                    "blockTorExitNode": false},
+                    
+   "ip4Whitelist": ["192.168.30.0/24", "10.0.2.0/24", "5.34.32.0/24"],
+   
+   "ip6Whitelist": ["2001:550:90a::/48", "::1/128"]
+}
\ No newline at end of file
diff --git 
a/traffic_router/core/src/test/resources/anonymous_ip_no_whitelist.json 
b/traffic_router/core/src/test/resources/anonymous_ip_no_whitelist.json
new file mode 100644
index 0000000..2f0f18e
--- /dev/null
+++ b/traffic_router/core/src/test/resources/anonymous_ip_no_whitelist.json
@@ -0,0 +1,12 @@
+{
+
+   "customer": "Cisco",
+   "version": "1",
+   "date" : "2017-05-23 03:28:25",
+   "name": "Anonymous IP Blocking Policy",
+
+   "anonymousIp": { "blockAnonymousVPN": true,
+                    "blockHostingProvider": true, 
+                    "blockPublicProxy": true,
+                    "blockTorExitNode": false},
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
els...@apache.org.

Reply via email to