PeterRyder closed pull request #736: Anonymous IP TR Implementation
URL: https://github.com/apache/incubator-trafficcontrol/pull/736
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
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 7128a4ac5..6ce39da74 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
@@ -58,6 +58,9 @@
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 {
@@ -77,6 +80,8 @@
private NetworkUpdater networkUpdater;
private FederationsWatcher federationsWatcher;
private RegionalGeoUpdater regionalGeoUpdater;
+ private AnonymousIpConfigUpdater anonymousIpConfigUpdater;
+ private AnonymousIpDatabaseUpdater anonymousIpDatabaseUpdater;
private SteeringWatcher steeringWatcher;
private CertificatesPoller certificatesPoller;
private CertificatesPublisher certificatesPublisher;
@@ -103,6 +108,14 @@ public RegionalGeoUpdater getRegionalGeoUpdater() {
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
JSONException, IOException {
isProcessing.set(true);
@@ -137,6 +150,7 @@ public boolean processConfig(final String jsonStr) throws
JSONException, IOExcep
parseGeolocationConfig(config);
parseCoverageZoneNetworkConfig(config);
parseRegionalGeoConfig(jo);
+ parseAnonymousIpConfig(jo);
final CacheRegister cacheRegister = new
CacheRegister();
final JSONObject deliveryServicesJson =
jo.getJSONObject("deliveryServices");
@@ -251,6 +265,14 @@ public void setRegionalGeoUpdater(final RegionalGeoUpdater
regionalGeoUpdater) {
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
@@ -507,6 +529,50 @@ private void parseCertificatesConfig(final JSONObject
config) {
}
}
+ 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 1001c26a8..4812265df 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
@@ -50,7 +50,7 @@
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;
@@ -85,6 +85,7 @@
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;
@@ -138,6 +139,7 @@ public DeliveryService(final String id, final JSONObject
dsJo) throws JSONExcept
} else {
LOGGER.info("DeliveryService '" + id + "' will use
default geolocation provider Maxmind");
}
+ this.anonymousIpEnabled =
dsJo.optBoolean("anonymousBlockingEnabled", false);
sslEnabled = dsJo.optBoolean("sslEnabled", false);
final JSONObject protocol = dsJo.optJSONObject("protocol");
@@ -595,6 +597,10 @@ public String getGeolocationProvider() {
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 000000000..6de381fb3
--- /dev/null
+++
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIp.java
@@ -0,0 +1,251 @@
+/*
+ * 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 java.net.URL;
+
+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;
+
+ private String redirectUrl;
+
+ 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);
+
+ if (config.has("redirectUrl")) {
+ anonymousIp.redirectUrl =
config.getString("redirectUrl");
+ }
+
+ 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);
+ if (AnonymousIp.getCurrentConfig().redirectUrl != null)
{
+ routeResult.setUrl(new
URL(AnonymousIp.getCurrentConfig().redirectUrl));
+ }
+ }
+ }
+}
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 000000000..ede90bc4e
--- /dev/null
+++
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpConfigUpdater.java
@@ -0,0 +1,51 @@
+/*
+ * 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 000000000..b70846b46
--- /dev/null
+++
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseService.java
@@ -0,0 +1,131 @@
+/*
+ * 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 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 000000000..2d63f2d19
--- /dev/null
+++
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseUpdater.java
@@ -0,0 +1,63 @@
+/*
+ * 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 000000000..0aec38915
--- /dev/null
+++
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelist.java
@@ -0,0 +1,62 @@
+/*
+ * 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 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 f628afdca..4d72ce205 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
@@ -104,7 +104,7 @@ public void setRegionalAlternateCount(final int
regionalAlternateCount) {
}
public static enum ResultType {
- ERROR, CZ, GEO, MISS, STATIC_ROUTE, DS_REDIRECT,
DS_MISS, INIT, FED, RGDENY, RGALT, GEO_REDIRECT
+ ERROR, CZ, GEO, MISS, STATIC_ROUTE, DS_REDIRECT,
DS_MISS, INIT, FED, RGDENY, RGALT, GEO_REDIRECT, 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 9d82eea87..3c9d6f2fa 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
@@ -65,6 +65,8 @@
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);
@@ -74,6 +76,7 @@
private final ZoneManager zoneManager;
private final GeolocationService geolocationService;
private final GeolocationService geolocationService6;
+ private final AnonymousIpDatabaseService anonymousIpService;
private final FederationRegistry federationRegistry;
private final boolean consistentDNSRouting;
@@ -87,7 +90,8 @@
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,
@@ -95,6 +99,7 @@ public TrafficRouter(final CacheRegister cr,
this.cacheRegister = cr;
this.geolocationService = geolocationService;
this.geolocationService6 = geolocationService6;
+ this.anonymousIpService = anonymousIpService;
this.federationRegistry = federationRegistry;
this.consistentDNSRouting =
cr.getConfig().optBoolean("consistent.dns.routing", false); // previous/default
behavior
this.zoneManager = new ZoneManager(this, statTracker,
trafficOpsUtils, trafficRouterManager);
@@ -182,6 +187,10 @@ public GeolocationService getGeolocationService() {
return geolocationService;
}
+ public AnonymousIpDatabaseService getAnonymousIpDatabaseService() {
+ return anonymousIpService;
+ }
+
public Geolocation getLocation(final String clientIP) throws
GeolocationException {
return clientIP.contains(":") ?
geolocationService6.location(clientIP) : geolocationService.location(clientIP);
}
@@ -488,6 +497,7 @@ public HTTPRouteResult multiRoute(final HTTPRequest
request, final Track track)
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());
@@ -498,6 +508,7 @@ public HTTPRouteResult route(final HTTPRequest request,
final Track track) throw
}
}
+ @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
public HTTPRouteResult singleRoute(final HTTPRequest request, final
Track track) throws MalformedURLException, GeolocationException {
final DeliveryService deliveryService =
getDeliveryService(request, track);
@@ -530,6 +541,16 @@ public HTTPRouteResult singleRoute(final HTTPRequest
request, final Track track)
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 e8930d083..99599b571 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
@@ -33,6 +33,7 @@
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);
@@ -43,6 +44,7 @@
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;
@@ -99,7 +101,7 @@ public void setCacheRegister(final CacheRegister
cacheRegister) throws IOExcepti
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) {
@@ -127,6 +129,10 @@ public void setGeolocationService6(final
GeolocationService geolocationService)
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 4e3f869b8..02a56d072 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>
@@ -110,6 +111,8 @@
<property name="geolocationDatabaseUpdater"
ref="geolocationDatabaseUpdater" />
<property name="networkUpdater" ref="networkUpdater" />
<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" />
@@ -126,6 +129,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"/>
@@ -153,6 +157,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 000000000..c68276094
--- /dev/null
+++
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpDatabaseServiceTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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 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 000000000..7fe97f7ec
--- /dev/null
+++
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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 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 000000000..eaf6af3a3
--- /dev/null
+++
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/loc/AnonymousIpWhitelistTest.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 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 000000000..05f686aa1
--- /dev/null
+++ b/traffic_router/core/src/test/resources/anonymous_ip.json
@@ -0,0 +1,18 @@
+{
+
+ "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"],
+
+ "redirectUrl": "http://youvebeenblocked.com"
+}
\ 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 000000000..1e0ba93b9
--- /dev/null
+++ b/traffic_router/core/src/test/resources/anonymous_ip_no_whitelist.json
@@ -0,0 +1,13 @@
+{
+
+ "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},
+ "redirectUrl": "http://youvebeenblocked.com"
+}
\ No newline at end of file
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services