From aa19a9a7415c717ff2152731b82b8c46338a3bd0 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Fri, 19 Jun 2015 11:46:47 +1000 Subject: [PATCH 01/24] Preload an HSTS domain list from chromium This resolves the first part of servo/servo#6105. The remaining part is to update the list based on the STS headers from the server. --- .gitignore | 1 + components/net/resource_task.rs | 88 +++++++++++++++++++- python/servo/bootstrap_commands.py | 92 +++++++++++++++++---- python/servo/command_base.py | 2 + tests/unit/net/resource_task.rs | 124 ++++++++++++++++++++++++++++- 5 files changed, 287 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index a21c4e30a17..0354c3e17f3 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ Servo.app .config.mk.last parser.out /glfw +hsts_preload.json diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 7c97b5449b1..59b15d53ead 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -17,21 +17,24 @@ use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, Respo use net_traits::ProgressMsg::Done; use util::opts; use util::task::spawn_named; +use util::resource_files::read_resource_file; use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; use hyper::mime::{Mime, TopLevel, SubLevel}; +use rustc_serialize::json::{decode}; + use std::borrow::ToOwned; use std::boxed::FnBox; use std::collections::HashMap; use std::env; use std::fs::File; use std::io::{BufReader, Read}; +use std::str::{FromStr, from_utf8}; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; - static mut HOST_TABLE: Option<*mut HashMap> = None; pub fn global_init() { @@ -152,17 +155,86 @@ pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result } } +fn preload_hsts_domains() -> Option { + match read_resource_file(&["hsts_preload.json"]) { + Ok(bytes) => { + match from_utf8(&bytes) { + Ok(hsts_preload_content) => { + HSTSList::new_from_preload(hsts_preload_content) + }, + Err(_) => None + } + }, + Err(_) => None + } +} + /// Create a ResourceTask pub fn new_resource_task(user_agent: Option, devtools_chan: Option>) -> ResourceTask { + let hsts_preload = preload_hsts_domains(); + let (setup_chan, setup_port) = channel(); let setup_chan_clone = setup_chan.clone(); spawn_named("ResourceManager".to_owned(), move || { - ResourceManager::new(setup_port, user_agent, setup_chan_clone, devtools_chan).start(); + ResourceManager::new(setup_port, user_agent, setup_chan_clone, hsts_preload, devtools_chan).start(); }); setup_chan } +#[derive(RustcDecodable, RustcEncodable)] +pub struct HSTSEntry { + pub host: String, + pub include_subdomains: bool +} + +#[derive(RustcDecodable, RustcEncodable)] +pub struct HSTSList { + pub entries: Vec +} + +impl HSTSList { + pub fn new_from_preload(preload_content: &str) -> Option { + match decode(preload_content) { + Ok(list) => Some(list), + Err(_) => None + } + } + + pub fn always_secure(&self, host: &str) -> bool { + // TODO - Should this be faster than O(n)? The HSTS list is only a few + // hundred or maybe thousand entries... + self.entries.iter().any(|e| { + if e.include_subdomains { + host.ends_with(&format!(".{}", e.host)) || e.host == host + } else { + e.host == host + } + }) + } + + + pub fn make_hsts_secure(&self, load_data: LoadData) -> LoadData { + if let Some(h) = load_data.url.domain() { + if self.always_secure(h) { + match &*load_data.url.scheme { + "http" => { + let mut secure_load_data = load_data.clone(); + let mut secure_url = load_data.url.clone(); + secure_url.scheme = "https".to_string(); + secure_load_data.url = secure_url; + + return secure_load_data + }, + _ => () + }; + } + } + + load_data + } +} + pub fn parse_hostsfile(hostsfile_content: &str) -> Box> { let ipv4_regex = regex!( r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); @@ -204,13 +276,15 @@ struct ResourceManager { cookie_storage: CookieStorage, resource_task: Sender, mime_classifier: Arc, - devtools_chan: Option> + devtools_chan: Option>, + hsts_list: Option } impl ResourceManager { fn new(from_client: Receiver, user_agent: Option, resource_task: Sender, + hsts_list: Option, devtools_channel: Option>) -> ResourceManager { ResourceManager { from_client: from_client, @@ -218,7 +292,8 @@ impl ResourceManager { cookie_storage: CookieStorage::new(), resource_task: resource_task, mime_classifier: Arc::new(MIMEClassifier::new()), - devtools_chan: devtools_channel + devtools_chan: devtools_channel, + hsts_list: hsts_list } } } @@ -262,6 +337,11 @@ impl ResourceManager { load_data.preserved_headers.set(UserAgent(ua.clone())); }); + match self.hsts_list { + Some(ref l) => load_data = l.make_hsts_secure(load_data), + _ => () + } + fn from_factory(factory: fn(LoadData, LoadConsumer, Arc)) -> Box) + Send> { box move |load_data, senders, classifier| { diff --git a/python/servo/bootstrap_commands.py b/python/servo/bootstrap_commands.py index 5cf2f39c927..67345fb1fdd 100644 --- a/python/servo/bootstrap_commands.py +++ b/python/servo/bootstrap_commands.py @@ -9,11 +9,15 @@ from __future__ import print_function, unicode_literals +import base64 +import json import os import os.path as path +import re import shutil import subprocess import sys +import StringIO import tarfile import urllib2 from distutils.version import LooseVersion @@ -27,27 +31,33 @@ from mach.decorators import ( from servo.command_base import CommandBase, cd, host_triple -def download(desc, src, dst): +def download(desc, src, writer): print("Downloading %s..." % desc) dumb = (os.environ.get("TERM") == "dumb") or (not sys.stdout.isatty()) try: resp = urllib2.urlopen(src) - fsize = int(resp.info().getheader('Content-Length').strip()) + + fsize = None + if resp.info().getheader('Content-Length'): + fsize = int(resp.info().getheader('Content-Length').strip()) + recved = 0 chunk_size = 8192 - with open(dst, 'wb') as fd: - while True: - chunk = resp.read(chunk_size) - if not chunk: - break - recved += len(chunk) - if not dumb: + while True: + chunk = resp.read(chunk_size) + if not chunk: break + recved += len(chunk) + if not dumb: + if fsize is not None: pct = recved * 100.0 / fsize print("\rDownloading %s: %5.1f%%" % (desc, pct), end="") - sys.stdout.flush() - fd.write(chunk) + else: + print("\rDownloading %s" % desc, end="") + + sys.stdout.flush() + writer.write(chunk) if not dumb: print() @@ -62,6 +72,14 @@ def download(desc, src, dst): sys.exit(1) +def download_file(desc, src, dst): + with open(dst, 'wb') as fd: + download(desc, src, fd) + +def download_bytes(desc, src): + content_writer = StringIO.StringIO() + download(desc, src, content_writer) + return content_writer.getvalue() def extract(src, dst, movedir=None): tarfile.open(src).extractall(dst) @@ -111,7 +129,7 @@ class MachCommands(CommandBase): % self.rust_snapshot_path()) tgz_file = rust_dir + '.tar.gz' - download("Rust snapshot", snapshot_url, tgz_file) + download_file("Rust snapshot", snapshot_url, tgz_file) print("Extracting Rust snapshot...") snap_dir = path.join(rust_dir, @@ -142,7 +160,7 @@ class MachCommands(CommandBase): % docs_name) tgz_file = path.join(hash_dir, 'doc.tar.gz') - download("Rust docs", snapshot_url, tgz_file) + download_file("Rust docs", snapshot_url, tgz_file) print("Extracting Rust docs...") temp_dir = path.join(hash_dir, "temp_docs") @@ -166,7 +184,7 @@ class MachCommands(CommandBase): self.cargo_build_id()) if not force and path.exists(path.join(cargo_dir, "bin", "cargo")): print("Cargo already downloaded.", end=" ") - print("Use |bootstrap_cargo --force| to download again.") + print("Use |bootstrap-cargo --force| to download again.") return if path.isdir(cargo_dir): @@ -177,7 +195,7 @@ class MachCommands(CommandBase): nightly_url = "https://static-rust-lang-org.s3.amazonaws.com/cargo-dist/%s/%s" % \ (self.cargo_build_id(), tgz_file) - download("Cargo nightly", nightly_url, tgz_file) + download_file("Cargo nightly", nightly_url, tgz_file) print("Extracting Cargo nightly...") nightly_dir = path.join(cargo_dir, @@ -185,6 +203,50 @@ class MachCommands(CommandBase): extract(tgz_file, cargo_dir, movedir=nightly_dir) print("Cargo ready.") + @Command('bootstrap-hsts-preload', + description='Download the HSTS preload list', + category='bootstrap') + @CommandArgument('--force', '-f', + action='store_true', + help='Force download even if HSTS list already exist') + def bootstrap_hsts_preload(self, force=False): + preload_filename = "hsts_preload.json" + preload_path = path.join(self.context.topdir, "resources") + + if not force and path.exists(path.join(preload_path, preload_filename)): + print("HSTS preload list already downloaded.", end=" ") + print("Use |bootstrap-hsts-preload --force| to download again.") + return + + chromium_hsts_url = "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT" + + try: + content_base64 = download_bytes("Chromium HSTS preload list", chromium_hsts_url) + except URLError, e: + print("Unable to download chromium HSTS preload list, are you connected to the internet?") + sys.exit(1) + + content_decoded = base64.b64decode(content_base64) + content_json = re.sub(r'//.*$', '', content_decoded, flags=re.MULTILINE) + + try: + pins_and_static_preloads = json.loads(content_json) + entries = { + "entries": [ + { + "host": e["name"], + "include_subdomains": e.get("include_subdomains", False) + } + for e in pins_and_static_preloads["entries"] + ] + } + + with open(path.join(preload_path, preload_filename), 'w') as fd: + json.dump(entries, fd, indent=4) + except ValueError, e: + print("Unable to parse chromium HSTS preload list, has the format changed?") + sys.exit(1) + @Command('update-submodules', description='Update submodules', category='bootstrap') diff --git a/python/servo/command_base.py b/python/servo/command_base.py index 7c41fa42196..b4ba795691f 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -324,5 +324,7 @@ class CommandBase(object): not path.exists(path.join( self.config["tools"]["cargo-root"], "cargo", "bin", "cargo")): Registrar.dispatch("bootstrap-cargo", context=self.context) + if not path.exists(path.join("resources", "hsts_preload.json")): + Registrar.dispatch("bootstrap-hsts-preload", context=self.context) self.context.bootstrapped = True diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 5abfc40ba45..0c73fac39ac 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use net::resource_task::{new_resource_task, parse_hostsfile, replace_hosts}; +use net::resource_task::{ + new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry +}; use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::ProgressMsg; use std::borrow::ToOwned; @@ -17,6 +19,126 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } +#[test] +fn test_parse_hsts_preload_should_return_none_when_json_invalid() { + let mock_preload_content = "derp"; + match HSTSList::new_from_preload(mock_preload_content) { + Some(_) => assert!(false, "preload list should not have parsed"), + None => assert!(true) + } +} + +#[test] +fn test_parse_hsts_preload_should_return_none_when_json_contains_no_entries_key() { + let mock_preload_content = "{\"nothing\": \"to see here\"}"; + match HSTSList::new_from_preload(mock_preload_content) { + Some(_) => assert!(false, "preload list should not have parsed"), + None => assert!(true) + } +} + +#[test] +fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { + let mock_preload_content = "{\ + \"entries\": [\ + {\"host\": \"mozilla.org\",\ + \"include_subdomains\": false}\ + ]\ + }"; + let hsts_list = HSTSList::new_from_preload(mock_preload_content); + let entries = hsts_list.unwrap().entries; + + assert!(entries.get(0).unwrap().host == "mozilla.org"); + assert!(entries.get(0).unwrap().include_subdomains == false); +} + +#[test] +fn test_hsts_list_with_no_entries_does_not_always_secure() { + let hsts_list = HSTSList { + entries: Vec::new() + }; + + assert!(hsts_list.always_secure("mozilla.org") == false); +} + +#[test] +fn test_hsts_list_with_exact_domain_entry_is_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + }; + + assert!(hsts_list.always_secure("mozilla.org") == true); +} + +#[test] +fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + }; + + assert!(hsts_list.always_secure("servo.mozilla.org") == true); +} + +#[test] +fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + }; + + assert!(hsts_list.always_secure("servo.mozilla.org") == false); +} + +#[test] +fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + }; + + assert!(hsts_list.always_secure("servo-mozilla.org") == false); +} + +#[test] +fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + }; + + assert!(hsts_list.always_secure("mozilla.org") == true); +} + +#[test] +fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { + let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + }; + let secure_load_data = hsts_list.make_hsts_secure(load_data); + + assert!(&secure_load_data.url.scheme == "file"); +} + +#[test] +fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() { + let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None); + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + }; + let secure_load_data = hsts_list.make_hsts_secure(load_data); + + assert!(&secure_load_data.url.scheme == "https"); +} + +#[test] +fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() { + let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + }; + let secure_load_data = hsts_list.make_hsts_secure(load_data); + + assert!(&secure_load_data.url.scheme == "https"); +} + #[test] fn test_bad_scheme() { let resource_task = new_resource_task(None, None); From d2f35555b95c15ebec2be137df1fd8fa8ec3b9bb Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Mon, 22 Jun 2015 13:46:44 -0700 Subject: [PATCH 02/24] Implement mutable HSTS list This prepares the resource task to update the HSTS list when it sees STS headers. This will allow full HSTS support for servo/servo#6105 when the resource task implements the header checking --- components/net/resource_task.rs | 84 +++++++++++++++++++++++++++------ tests/unit/net/resource_task.rs | 57 ++++++++++++++++++++++ 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 59b15d53ead..2e7fbe6cdd3 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -13,11 +13,12 @@ use cookie; use mime_classifier::MIMEClassifier; use net_traits::{ControlMsg, LoadData, LoadResponse, LoadConsumer}; -use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, ResponseAction}; +use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, ResponseAction, CookieSource}; use net_traits::ProgressMsg::Done; use util::opts; use util::task::spawn_named; use util::resource_files::read_resource_file; +use url::Url; use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; @@ -188,6 +189,16 @@ pub struct HSTSEntry { pub include_subdomains: bool } +impl HSTSEntry { + fn matches_domain(&self, host: &str) -> bool { + self.host == host + } + + fn matches_subdomain(&self, host: &str) -> bool { + host.ends_with(&format!(".{}", self.host)) + } +} + #[derive(RustcDecodable, RustcEncodable)] pub struct HSTSList { pub entries: Vec @@ -204,15 +215,56 @@ impl HSTSList { pub fn always_secure(&self, host: &str) -> bool { // TODO - Should this be faster than O(n)? The HSTS list is only a few // hundred or maybe thousand entries... + // + // Could optimise by searching for exact matches first (via a map or + // something), then checking for subdomains. self.entries.iter().any(|e| { if e.include_subdomains { - host.ends_with(&format!(".{}", e.host)) || e.host == host + e.matches_subdomain(host) || e.matches_domain(host) } else { - e.host == host + e.matches_domain(host) } }) } + fn has_domain(&self, host: String) -> bool { + self.entries.iter().any(|e| { + e.matches_domain(&host) + }) + } + + pub fn has_subdomain(&self, host: String) -> bool { + self.entries.iter().any(|e| { + e.matches_subdomain(&host) + }) + } + + pub fn push(&mut self, host: String, include_subdomains: bool) { + let have_domain = self.has_domain(host.clone()); + let have_subdomain = self.has_subdomain(host.clone()); + + if !have_domain && !have_subdomain { + self.entries.push(HSTSEntry { + host: host, + include_subdomains: include_subdomains + }); + } else if !have_subdomain { + self.entries = self.entries.iter().fold(Vec::new(), |mut m, e| { + let new = HSTSEntry { + host: host.clone(), + include_subdomains: include_subdomains + }; + + if e.matches_domain(&host) { + m.push(new); + } else { + m.push(new); + } + + m + }); + } + } pub fn make_hsts_secure(&self, load_data: LoadData) -> LoadData { if let Some(h) = load_data.url.domain() { @@ -300,27 +352,31 @@ impl ResourceManager { impl ResourceManager { + fn set_cookies_for_url(&mut self, request: Url, cookie_list: String, source: CookieSource) { + let header = Header::parse_header(&[cookie_list.into_bytes()]); + if let Ok(SetCookie(cookies)) = header { + for bare_cookie in cookies.into_iter() { + if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) { + self.cookie_storage.push(cookie, source); + } + } + } + } + fn start(&mut self) { loop { match self.from_client.recv().unwrap() { ControlMsg::Load(load_data, consumer) => { - self.load(load_data, consumer) + self.load(load_data, consumer) } ControlMsg::SetCookiesForUrl(request, cookie_list, source) => { - let header = Header::parse_header(&[cookie_list.into_bytes()]); - if let Ok(SetCookie(cookies)) = header { - for bare_cookie in cookies.into_iter() { - if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) { - self.cookie_storage.push(cookie, source); - } - } - } + self.set_cookies_for_url(request, cookie_list, source) } ControlMsg::GetCookiesForUrl(url, consumer, source) => { - consumer.send(self.cookie_storage.cookies_for_url(&url, source)).unwrap(); + consumer.send(self.cookie_storage.cookies_for_url(&url, source)).unwrap(); } ControlMsg::Exit => { - break + break } } } diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 0c73fac39ac..38679fc2383 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -19,6 +19,63 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } +#[test] +fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { + let mut list = HSTSList { + entries: vec!(HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: true + }) + }; + + list.push("servo.mozilla.org".to_string(), false); + + assert!(list.entries.len() == 1) +} + +#[test] +fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { + let mut list = HSTSList { + entries: vec!(HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: true + }) + }; + + assert!(list.always_secure("servo.mozilla.org")); + + list.push("mozilla.org".to_string(), false); + + assert!(!list.always_secure("servo.mozilla.org")) +} + +#[test] +fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { + let mut list = HSTSList { + entries: vec!(HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false + }) + }; + + list.push("mozilla.org".to_string(), false); + + assert!(list.entries.len() == 1) +} + +#[test] +fn test_push_entry_to_hsts_list_should_add_an_entry() { + let mut list = HSTSList { + entries: Vec::new() + }; + + assert!(!list.always_secure("mozilla.org")); + + list.push("mozilla.org".to_string(), true); + + assert!(list.always_secure("mozilla.org")); +} + #[test] fn test_parse_hsts_preload_should_return_none_when_json_invalid() { let mock_preload_content = "derp"; From 72d443358769ec854c0dce40cc69fc94077d404d Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Mon, 22 Jun 2015 14:59:28 -0700 Subject: [PATCH 03/24] Do not allow IP address in HSTS list As per [rfc6797](https://tools.ietf.org/html/rfc6797#section-8.1.1), do not allow IPv4 or IPv6 addresses as host entries into the HSTS list. servo/servo#6105 --- components/net/resource_task.rs | 16 +++++++++++----- tests/unit/net/resource_task.rs | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 2e7fbe6cdd3..d9fef39209e 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -26,17 +26,22 @@ use hyper::mime::{Mime, TopLevel, SubLevel}; use rustc_serialize::json::{decode}; +use regex::Regex; use std::borrow::ToOwned; use std::boxed::FnBox; use std::collections::HashMap; use std::env; use std::fs::File; use std::io::{BufReader, Read}; -use std::str::{FromStr, from_utf8}; +use std::str::{from_utf8}; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; static mut HOST_TABLE: Option<*mut HashMap> = None; +static IPV4_REGEX: Regex = regex!( + r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" +); +static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); pub fn global_init() { //TODO: handle bad file path @@ -240,6 +245,10 @@ impl HSTSList { } pub fn push(&mut self, host: String, include_subdomains: bool) { + if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { + return + } + let have_domain = self.has_domain(host.clone()); let have_subdomain = self.has_subdomain(host.clone()); @@ -288,16 +297,13 @@ impl HSTSList { } pub fn parse_hostsfile(hostsfile_content: &str) -> Box> { - let ipv4_regex = regex!( - r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); - let ipv6_regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); let mut host_table = HashMap::new(); let lines: Vec<&str> = hostsfile_content.split('\n').collect(); for line in lines.iter() { let ip_host: Vec<&str> = line.trim().split(|c: char| c == ' ' || c == '\t').collect(); if ip_host.len() > 1 { - if !ipv4_regex.is_match(ip_host[0]) && !ipv6_regex.is_match(ip_host[0]) { continue; } + if !IPV4_REGEX.is_match(ip_host[0]) && !IPV6_REGEX.is_match(ip_host[0]) { continue; } let address = ip_host[0].to_owned(); for token in ip_host.iter().skip(1) { diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 38679fc2383..689e569f8e6 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -19,6 +19,28 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } +#[test] +fn test_push_entry_to_hsts_list_should_not_add_ipv6_addresses() { + let mut list = HSTSList { + entries: Vec::new() + }; + + list.push("2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false); + + assert!(list.entries.len() == 0) +} + +#[test] +fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() { + let mut list = HSTSList { + entries: Vec::new() + }; + + list.push("8.8.8.8".to_string(), false); + + assert!(list.entries.len() == 0) +} + #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { From 855a9487ae616331cc4f89aad0a802dfde6bf4a0 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Mon, 22 Jun 2015 15:23:26 -0700 Subject: [PATCH 04/24] Do not change the port when loading HSTS domain servo/servo#6105 --- tests/unit/net/resource_task.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 689e569f8e6..d61ec467a7f 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -185,6 +185,17 @@ fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { assert!(hsts_list.always_secure("mozilla.org") == true); } +#[test] +fn test_make_hsts_secure_does_not_change_explicit_port() { + let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); + let hsts_list = HSTSList { + entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + }; + let secure_load_data = hsts_list.make_hsts_secure(load_data); + + assert!(secure_load_data.url.port().unwrap() == 8080u16); +} + #[test] fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); From cb9b0c2a7ac815d13cee61a1c9e1abb24a5f1516 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Mon, 22 Jun 2015 15:48:05 -0700 Subject: [PATCH 05/24] Add max-age to HSTS entries Refactors API for pushing new entries on, and adds a max age. This does not add a check for the max-age, or remove old entries from the list. Instead this just adds the data-field. servo/servo#6105 --- components/net/resource_task.rs | 43 +++++++++++++++++------------- tests/unit/net/resource_task.rs | 47 ++++++++++++++------------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index d9fef39209e..04411fb0aed 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -36,6 +36,7 @@ use std::io::{BufReader, Read}; use std::str::{from_utf8}; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; +use time; static mut HOST_TABLE: Option<*mut HashMap> = None; static IPV4_REGEX: Regex = regex!( @@ -188,13 +189,24 @@ pub fn new_resource_task(user_agent: Option, setup_chan } -#[derive(RustcDecodable, RustcEncodable)] +#[derive(RustcDecodable, RustcEncodable, Clone)] pub struct HSTSEntry { pub host: String, - pub include_subdomains: bool + pub include_subdomains: bool, + pub max_age: Option, + timestamp: Option } impl HSTSEntry { + pub fn new(host: String, include_subdomains: bool, max_age: Option) -> HSTSEntry { + HSTSEntry { + host: host, + include_subdomains: include_subdomains, + max_age: max_age, + timestamp: Some(time::get_time().sec as u64) + } + } + fn matches_domain(&self, host: &str) -> bool { self.host == host } @@ -244,30 +256,25 @@ impl HSTSList { }) } - pub fn push(&mut self, host: String, include_subdomains: bool) { - if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { + pub fn push(&mut self, entry: HSTSEntry) { + if IPV4_REGEX.is_match(&entry.host) || IPV6_REGEX.is_match(&entry.host) { return } - let have_domain = self.has_domain(host.clone()); - let have_subdomain = self.has_subdomain(host.clone()); + let have_domain = self.has_domain(entry.host.clone()); + let have_subdomain = self.has_subdomain(entry.host.clone()); if !have_domain && !have_subdomain { - self.entries.push(HSTSEntry { - host: host, - include_subdomains: include_subdomains - }); + self.entries.push(entry); } else if !have_subdomain { self.entries = self.entries.iter().fold(Vec::new(), |mut m, e| { - let new = HSTSEntry { - host: host.clone(), - include_subdomains: include_subdomains - }; - - if e.matches_domain(&host) { - m.push(new); + if e.matches_domain(&entry.host) { + // Update the entry if there's an exact domain match. + m.push(entry.clone()); } else { - m.push(new); + // Ignore the new details if it's a subdomain match, or not + // a match at all. Just use the existing entry + m.push(e.clone()); } m diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index d61ec467a7f..3ed2823365b 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -25,7 +25,9 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv6_addresses() { entries: Vec::new() }; - list.push("2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false); + list.push(HSTSEntry::new( + "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false, None + )); assert!(list.entries.len() == 0) } @@ -36,7 +38,7 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() { entries: Vec::new() }; - list.push("8.8.8.8".to_string(), false); + list.push(HSTSEntry::new("8.8.8.8".to_string(), false, None)); assert!(list.entries.len() == 0) } @@ -44,13 +46,10 @@ fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() { #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { - entries: vec!(HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: true - }) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None)) }; - list.push("servo.mozilla.org".to_string(), false); + list.push(HSTSEntry::new("servo.mozilla.org".to_string(), false, None)); assert!(list.entries.len() == 1) } @@ -58,15 +57,12 @@ fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_a #[test] fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { let mut list = HSTSList { - entries: vec!(HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: true - }) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None)) }; assert!(list.always_secure("servo.mozilla.org")); - list.push("mozilla.org".to_string(), false); + list.push(HSTSEntry::new("mozilla.org".to_string(), false, None)); assert!(!list.always_secure("servo.mozilla.org")) } @@ -74,13 +70,10 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub #[test] fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { let mut list = HSTSList { - entries: vec!(HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: false - }) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, None)) }; - list.push("mozilla.org".to_string(), false); + list.push(HSTSEntry::new("mozilla.org".to_string(), false, None)); assert!(list.entries.len() == 1) } @@ -93,7 +86,7 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { assert!(!list.always_secure("mozilla.org")); - list.push("mozilla.org".to_string(), true); + list.push(HSTSEntry::new("mozilla.org".to_string(), true, None)); assert!(list.always_secure("mozilla.org")); } @@ -143,7 +136,7 @@ fn test_hsts_list_with_no_entries_does_not_always_secure() { #[test] fn test_hsts_list_with_exact_domain_entry_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] }; assert!(hsts_list.always_secure("mozilla.org") == true); @@ -152,7 +145,7 @@ fn test_hsts_list_with_exact_domain_entry_is_always_secure() { #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] }; assert!(hsts_list.always_secure("servo.mozilla.org") == true); @@ -161,7 +154,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secur #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] }; assert!(hsts_list.always_secure("servo.mozilla.org") == false); @@ -170,7 +163,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_ #[test] fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] }; assert!(hsts_list.always_secure("servo-mozilla.org") == false); @@ -179,7 +172,7 @@ fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secu #[test] fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] }; assert!(hsts_list.always_secure("mozilla.org") == true); @@ -189,7 +182,7 @@ fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { fn test_make_hsts_secure_does_not_change_explicit_port() { let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -200,7 +193,7 @@ fn test_make_hsts_secure_does_not_change_explicit_port() { fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -211,7 +204,7 @@ fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() { let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: true}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -222,7 +215,7 @@ fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomain fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() { let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry { host: "mozilla.org".to_string(), include_subdomains: false}] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); From 8d39fb6dcf70ff15330cba340dc5f167d3586903 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Mon, 22 Jun 2015 16:11:21 -0700 Subject: [PATCH 06/24] Shift checking for IP address host for HSTS entry to constructor servo/servo#6105 --- components/net/resource_task.rs | 20 +++++------ tests/unit/net/resource_task.rs | 62 ++++++++++++++++----------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 04411fb0aed..94277ba1c36 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -198,12 +198,16 @@ pub struct HSTSEntry { } impl HSTSEntry { - pub fn new(host: String, include_subdomains: bool, max_age: Option) -> HSTSEntry { - HSTSEntry { - host: host, - include_subdomains: include_subdomains, - max_age: max_age, - timestamp: Some(time::get_time().sec as u64) + pub fn new(host: String, include_subdomains: bool, max_age: Option) -> Option { + if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { + None + } else { + Some(HSTSEntry { + host: host, + include_subdomains: include_subdomains, + max_age: max_age, + timestamp: Some(time::get_time().sec as u64) + }) } } @@ -257,10 +261,6 @@ impl HSTSList { } pub fn push(&mut self, entry: HSTSEntry) { - if IPV4_REGEX.is_match(&entry.host) || IPV6_REGEX.is_match(&entry.host) { - return - } - let have_domain = self.has_domain(entry.host.clone()); let have_subdomain = self.has_subdomain(entry.host.clone()); diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 3ed2823365b..ecf4bea40d4 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -20,36 +20,36 @@ fn test_exit() { } #[test] -fn test_push_entry_to_hsts_list_should_not_add_ipv6_addresses() { - let mut list = HSTSList { - entries: Vec::new() - }; - - list.push(HSTSEntry::new( +fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { + let entry = HSTSEntry::new( "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false, None - )); + ); - assert!(list.entries.len() == 0) + match entry { + Some(_) => panic!("able to create HSTSEntry with IPv6 host"), + None => () + } } #[test] -fn test_push_entry_to_hsts_list_should_not_add_ipv4_addresses() { - let mut list = HSTSList { - entries: Vec::new() - }; +fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { + let entry = HSTSEntry::new( + "4.4.4.4".to_string(), false, None + ); - list.push(HSTSEntry::new("8.8.8.8".to_string(), false, None)); - - assert!(list.entries.len() == 0) + match entry { + Some(_) => panic!("able to create HSTSEntry with IPv6 host"), + None => () + } } #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None)) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()) }; - list.push(HSTSEntry::new("servo.mozilla.org".to_string(), false, None)); + list.push(HSTSEntry::new("servo.mozilla.org".to_string(), false, None).unwrap()); assert!(list.entries.len() == 1) } @@ -57,12 +57,12 @@ fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_a #[test] fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None)) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()) }; assert!(list.always_secure("servo.mozilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), false, None)); + list.push(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()); assert!(!list.always_secure("servo.mozilla.org")) } @@ -70,10 +70,10 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub #[test] fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, None)) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()) }; - list.push(HSTSEntry::new("mozilla.org".to_string(), false, None)); + list.push(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()); assert!(list.entries.len() == 1) } @@ -86,7 +86,7 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { assert!(!list.always_secure("mozilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), true, None)); + list.push(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()); assert!(list.always_secure("mozilla.org")); } @@ -136,7 +136,7 @@ fn test_hsts_list_with_no_entries_does_not_always_secure() { #[test] fn test_hsts_list_with_exact_domain_entry_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; assert!(hsts_list.always_secure("mozilla.org") == true); @@ -145,7 +145,7 @@ fn test_hsts_list_with_exact_domain_entry_is_always_secure() { #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; assert!(hsts_list.always_secure("servo.mozilla.org") == true); @@ -154,7 +154,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secur #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; assert!(hsts_list.always_secure("servo.mozilla.org") == false); @@ -163,7 +163,7 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_ #[test] fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; assert!(hsts_list.always_secure("servo-mozilla.org") == false); @@ -172,7 +172,7 @@ fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secu #[test] fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; assert!(hsts_list.always_secure("mozilla.org") == true); @@ -182,7 +182,7 @@ fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { fn test_make_hsts_secure_does_not_change_explicit_port() { let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -193,7 +193,7 @@ fn test_make_hsts_secure_does_not_change_explicit_port() { fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -204,7 +204,7 @@ fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() { let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); @@ -215,7 +215,7 @@ fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomain fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() { let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None)] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; let secure_load_data = hsts_list.make_hsts_secure(load_data); From 15c90a58b20a085f673dcb543ce8ae850bfc2f1b Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Tue, 23 Jun 2015 11:57:28 -0700 Subject: [PATCH 07/24] Expire HSTS entries that have exceeded their max-age servo/servo#6105 --- components/net/resource_task.rs | 18 +++++++++--- components/servo/Cargo.lock | 1 + tests/unit/net/Cargo.toml | 1 + tests/unit/net/lib.rs | 1 + tests/unit/net/resource_task.rs | 51 +++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 4 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 94277ba1c36..a5f795db898 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -194,7 +194,7 @@ pub struct HSTSEntry { pub host: String, pub include_subdomains: bool, pub max_age: Option, - timestamp: Option + pub timestamp: Option } impl HSTSEntry { @@ -211,12 +211,22 @@ impl HSTSEntry { } } + pub fn is_expired(&self) -> bool { + match (self.max_age, self.timestamp) { + (Some(max_age), Some(timestamp)) => { + (time::get_time().sec as u64) - timestamp > max_age + }, + + _ => false + } + } + fn matches_domain(&self, host: &str) -> bool { - self.host == host + !self.is_expired() && self.host == host } fn matches_subdomain(&self, host: &str) -> bool { - host.ends_with(&format!(".{}", self.host)) + !self.is_expired() && host.ends_with(&format!(".{}", self.host)) } } @@ -254,7 +264,7 @@ impl HSTSList { }) } - pub fn has_subdomain(&self, host: String) -> bool { + fn has_subdomain(&self, host: String) -> bool { self.entries.iter().any(|e| { e.matches_subdomain(&host) }) diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 568a41f5e7f..3c87137b941 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -876,6 +876,7 @@ dependencies = [ "net 0.0.1", "net_traits 0.0.1", "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] diff --git a/tests/unit/net/Cargo.toml b/tests/unit/net/Cargo.toml index eb2bffaac4d..5e9608356c7 100644 --- a/tests/unit/net/Cargo.toml +++ b/tests/unit/net/Cargo.toml @@ -21,3 +21,4 @@ path = "../../../components/util" cookie = "0.1" hyper = "0.6" url = "0.2" +time = "0.1" diff --git a/tests/unit/net/lib.rs b/tests/unit/net/lib.rs index f9c11c958a3..335cbd721a6 100644 --- a/tests/unit/net/lib.rs +++ b/tests/unit/net/lib.rs @@ -8,6 +8,7 @@ extern crate net; extern crate net_traits; extern crate url; extern crate util; +extern crate time; #[cfg(test)] mod cookie; #[cfg(test)] mod data_loader; diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index ecf4bea40d4..50ea0780347 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -11,6 +11,7 @@ use std::borrow::ToOwned; use std::collections::HashMap; use std::sync::mpsc::channel; use url::Url; +use time; #[test] @@ -19,6 +20,42 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } +#[test] +fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(20), + timestamp: None + }; + + assert!(!entry.is_expired()); +} + +#[test] +fn test_hsts_entry_is_not_expired_when_it_has_no_max_age() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: None, + timestamp: Some(time::get_time().sec as u64) + }; + + assert!(!entry.is_expired()); +} + +#[test] +fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(10), + timestamp: Some(time::get_time().sec as u64 - 20u64) + }; + + assert!(entry.is_expired()); +} + #[test] fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { let entry = HSTSEntry::new( @@ -178,6 +215,20 @@ fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { assert!(hsts_list.always_secure("mozilla.org") == true); } +#[test] +fn test_hsts_list_with_expired_entry_is_not_always_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(20), + timestamp: Some(time::get_time().sec as u64 - 100u64) + }] + }; + + assert!(!hsts_list.always_secure("mozilla.org")); +} + #[test] fn test_make_hsts_secure_does_not_change_explicit_port() { let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); From 690ac636eb82c1fe14e84876e38a0cb5e5be6a71 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Tue, 23 Jun 2015 14:59:23 -0700 Subject: [PATCH 08/24] Rename/refactor --- components/net/resource_task.rs | 46 +++++++++++--------- tests/unit/net/resource_task.rs | 76 ++++++++++++--------------------- 2 files changed, 53 insertions(+), 69 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index a5f795db898..562117f2ed4 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -243,7 +243,7 @@ impl HSTSList { } } - pub fn always_secure(&self, host: &str) -> bool { + pub fn is_host_secure(&self, host: &str) -> bool { // TODO - Should this be faster than O(n)? The HSTS list is only a few // hundred or maybe thousand entries... // @@ -291,25 +291,23 @@ impl HSTSList { }); } } +} - pub fn make_hsts_secure(&self, load_data: LoadData) -> LoadData { - if let Some(h) = load_data.url.domain() { - if self.always_secure(h) { - match &*load_data.url.scheme { - "http" => { - let mut secure_load_data = load_data.clone(); - let mut secure_url = load_data.url.clone(); - secure_url.scheme = "https".to_string(); - secure_load_data.url = secure_url; +pub fn secure_load_data(load_data: &LoadData) -> LoadData { + if let Some(h) = load_data.url.domain() { + match &*load_data.url.scheme { + "http" => { + let mut secure_load_data = load_data.clone(); + let mut secure_url = load_data.url.clone(); + secure_url.scheme = "https".to_string(); + secure_load_data.url = secure_url; - return secure_load_data - }, - _ => () - }; - } + secure_load_data + }, + _ => load_data.clone() } - - load_data + } else { + load_data.clone() } } @@ -416,10 +414,16 @@ impl ResourceManager { load_data.preserved_headers.set(UserAgent(ua.clone())); }); - match self.hsts_list { - Some(ref l) => load_data = l.make_hsts_secure(load_data), - _ => () - } + load_data = match (self.hsts_list.as_ref(), load_data.url.domain()) { + (Some(ref l), Some(ref h)) => { + if l.is_host_secure(h) { + secure_load_data(&load_data) + } else { + load_data.clone() + } + }, + _ => load_data.clone() + }; fn from_factory(factory: fn(LoadData, LoadConsumer, Arc)) -> Box) + Send> { diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 50ea0780347..03fe296a053 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use net::resource_task::{ - new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry + new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry, secure_load_data }; use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::ProgressMsg; @@ -97,11 +97,11 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()) }; - assert!(list.always_secure("servo.mozilla.org")); + assert!(list.is_host_secure("servo.mozilla.org")); list.push(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()); - assert!(!list.always_secure("servo.mozilla.org")) + assert!(!list.is_host_secure("servo.mozilla.org")) } #[test] @@ -121,11 +121,11 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { entries: Vec::new() }; - assert!(!list.always_secure("mozilla.org")); + assert!(!list.is_host_secure("mozilla.org")); list.push(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()); - assert!(list.always_secure("mozilla.org")); + assert!(list.is_host_secure("mozilla.org")); } #[test] @@ -162,61 +162,61 @@ fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { } #[test] -fn test_hsts_list_with_no_entries_does_not_always_secure() { +fn test_hsts_list_with_no_entries_does_not_is_host_secure() { let hsts_list = HSTSList { entries: Vec::new() }; - assert!(hsts_list.always_secure("mozilla.org") == false); + assert!(hsts_list.is_host_secure("mozilla.org") == false); } #[test] -fn test_hsts_list_with_exact_domain_entry_is_always_secure() { +fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; - assert!(hsts_list.always_secure("mozilla.org") == true); + assert!(hsts_list.is_host_secure("mozilla.org") == true); } #[test] -fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_always_secure() { +fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; - assert!(hsts_list.always_secure("servo.mozilla.org") == true); + assert!(hsts_list.is_host_secure("servo.mozilla.org") == true); } #[test] -fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_always_secure() { +fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] }; - assert!(hsts_list.always_secure("servo.mozilla.org") == false); + assert!(hsts_list.is_host_secure("servo.mozilla.org") == false); } #[test] -fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_always_secure() { +fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; - assert!(hsts_list.always_secure("servo-mozilla.org") == false); + assert!(hsts_list.is_host_secure("servo-mozilla.org") == false); } #[test] -fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_always_secure() { +fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] }; - assert!(hsts_list.always_secure("mozilla.org") == true); + assert!(hsts_list.is_host_secure("mozilla.org") == true); } #[test] -fn test_hsts_list_with_expired_entry_is_not_always_secure() { +fn test_hsts_list_with_expired_entry_is_not_is_host_secure() { let hsts_list = HSTSList { entries: vec![HSTSEntry { host: "mozilla.org".to_string(), @@ -226,51 +226,31 @@ fn test_hsts_list_with_expired_entry_is_not_always_secure() { }] }; - assert!(!hsts_list.always_secure("mozilla.org")); + assert!(!hsts_list.is_host_secure("mozilla.org")); } #[test] -fn test_make_hsts_secure_does_not_change_explicit_port() { +fn test_secure_load_data_does_not_change_explicit_port() { let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] - }; - let secure_load_data = hsts_list.make_hsts_secure(load_data); + let secure = secure_load_data(&load_data); - assert!(secure_load_data.url.port().unwrap() == 8080u16); + assert!(secure.url.port().unwrap() == 8080u16); } #[test] -fn test_make_hsts_secure_doesnt_affect_non_http_schemas() { +fn test_secure_load_data_does_not_affect_non_http_schemas() { let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] - }; - let secure_load_data = hsts_list.make_hsts_secure(load_data); + let secure = secure_load_data(&load_data); - assert!(&secure_load_data.url.scheme == "file"); + assert!(&secure.url.scheme == "file"); } #[test] -fn test_make_hsts_secure_sets_secure_schema_on_subdomains_when_include_subdomains_is_true() { - let load_data = LoadData::new(Url::parse("http://servo.mozilla.org").unwrap(), None); - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] - }; - let secure_load_data = hsts_list.make_hsts_secure(load_data); - - assert!(&secure_load_data.url.scheme == "https"); -} - -#[test] -fn test_make_hsts_secure_forces_an_http_host_in_list_to_https() { +fn test_secure_load_data_forces_an_http_host_in_list_to_https() { let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] - }; - let secure_load_data = hsts_list.make_hsts_secure(load_data); + let secure = secure_load_data(&load_data); - assert!(&secure_load_data.url.scheme == "https"); + assert!(&secure.url.scheme == "https"); } #[test] From ff1777e446c4358ea1e27fc7970c6c3a61d0d32d Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Tue, 23 Jun 2015 16:00:30 -0700 Subject: [PATCH 09/24] Evict HSTS entries when a max-age of 0 is seen --- components/net/resource_task.rs | 2 +- tests/unit/net/resource_task.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 562117f2ed4..a34c1129712 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -214,7 +214,7 @@ impl HSTSEntry { pub fn is_expired(&self) -> bool { match (self.max_age, self.timestamp) { (Some(max_age), Some(timestamp)) => { - (time::get_time().sec as u64) - timestamp > max_age + (time::get_time().sec as u64) - timestamp >= max_age }, _ => false diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 03fe296a053..35f2cb667e3 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -80,6 +80,17 @@ fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { } } +#[test] +fn test_push_entry_with_0_max_age_evicts_entry_from_list() { + let mut list = HSTSList { + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, Some(500000u64)).unwrap()) + }; + + list.push(HSTSEntry::new("mozilla.org".to_string(), false, Some(0)).unwrap()); + + assert!(list.is_host_secure("mozilla.org") == false) +} + #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { From f284181781614f2be7e057dc778428efcd4b5058 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Wed, 24 Jun 2015 11:15:20 -0700 Subject: [PATCH 10/24] Abstract out ResourceManager messaging from impl De-coupling makes testing a bit easier. --- components/net/resource_task.rs | 92 +++++++++++++++++++++------------ tests/unit/net/resource_task.rs | 23 ++++++++- 2 files changed, 80 insertions(+), 35 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index a34c1129712..41b23a2eb82 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -184,7 +184,16 @@ pub fn new_resource_task(user_agent: Option, let (setup_chan, setup_port) = channel(); let setup_chan_clone = setup_chan.clone(); spawn_named("ResourceManager".to_owned(), move || { - ResourceManager::new(setup_port, user_agent, setup_chan_clone, hsts_preload, devtools_chan).start(); + let resource_manager = ResourceManager::new( + user_agent, setup_chan_clone, hsts_preload, devtools_chan + ); + + let mut channel_manager = ResourceChannelManager { + from_client: setup_port, + resource_manager: resource_manager + }; + + channel_manager.start(); }); setup_chan } @@ -294,20 +303,16 @@ impl HSTSList { } pub fn secure_load_data(load_data: &LoadData) -> LoadData { - if let Some(h) = load_data.url.domain() { - match &*load_data.url.scheme { - "http" => { - let mut secure_load_data = load_data.clone(); - let mut secure_url = load_data.url.clone(); - secure_url.scheme = "https".to_string(); - secure_load_data.url = secure_url; + match &*load_data.url.scheme { + "http" => { + let mut secure_load_data = load_data.clone(); + let mut secure_url = load_data.url.clone(); + secure_url.scheme = "https".to_string(); + secure_load_data.url = secure_url; - secure_load_data - }, - _ => load_data.clone() - } - } else { - load_data.clone() + secure_load_data + }, + _ => load_data.clone() } } @@ -343,10 +348,36 @@ pub fn replace_hosts(mut load_data: LoadData, host_table: *mut HashMap, + resource_manager: ResourceManager +} + +impl ResourceChannelManager { + fn start(&mut self) { + loop { + match self.from_client.recv().unwrap() { + ControlMsg::Load(load_data, consumer) => { + self.resource_manager.load(load_data, consumer) + } + ControlMsg::SetCookiesForUrl(request, cookie_list, source) => { + self.resource_manager.set_cookies_for_url(request, cookie_list, source) + } + ControlMsg::GetCookiesForUrl(url, consumer, source) => { + consumer.send(self.resource_manager.cookie_storage.cookies_for_url(&url, source)).unwrap(); + } + ControlMsg::Exit => { + break + } + } + } + } +} + +pub struct ResourceManager { user_agent: Option, cookie_storage: CookieStorage, + // TODO: Can this be de-coupled? resource_task: Sender, mime_classifier: Arc, devtools_chan: Option>, @@ -354,13 +385,11 @@ struct ResourceManager { } impl ResourceManager { - fn new(from_client: Receiver, - user_agent: Option, + pub fn new(user_agent: Option, resource_task: Sender, hsts_list: Option, devtools_channel: Option>) -> ResourceManager { ResourceManager { - from_client: from_client, user_agent: user_agent, cookie_storage: CookieStorage::new(), resource_task: resource_task, @@ -384,22 +413,17 @@ impl ResourceManager { } } - fn start(&mut self) { - loop { - match self.from_client.recv().unwrap() { - ControlMsg::Load(load_data, consumer) => { - self.load(load_data, consumer) - } - ControlMsg::SetCookiesForUrl(request, cookie_list, source) => { - self.set_cookies_for_url(request, cookie_list, source) - } - ControlMsg::GetCookiesForUrl(url, consumer, source) => { - consumer.send(self.cookie_storage.cookies_for_url(&url, source)).unwrap(); - } - ControlMsg::Exit => { - break - } - } + pub fn is_host_sts(&self, host: &str) -> bool { + match self.hsts_list.as_ref() { + Some(list) => list.is_host_secure(host), + None => false + } + } + + pub fn add_hsts_entry(&mut self, entry: HSTSEntry) { + match self.hsts_list.as_mut() { + Some(list) => list.push(entry), + None => () } } diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 35f2cb667e3..9f72b4d54ed 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use net::resource_task::{ - new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry, secure_load_data + new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry, secure_load_data, + ResourceManager }; use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::ProgressMsg; @@ -20,6 +21,26 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } +#[test] +fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { + let list = HSTSList { + entries: Vec::new() + }; + + let (tx, _) = channel(); + let mut manager = ResourceManager::new(None, tx, Some(list), None); + + let entry = HSTSEntry::new( + "mozilla.org".to_string(), false, None + ); + + assert!(!manager.is_host_sts("mozilla.org")); + + manager.add_hsts_entry(entry.unwrap()); + + assert!(manager.is_host_sts("mozilla.org")) +} + #[test] fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() { let entry = HSTSEntry { From 795454fb81af3ff894c42cc3da13bab1616af0fb Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Wed, 24 Jun 2015 11:30:08 -0700 Subject: [PATCH 11/24] Adds control message for HSTS headers --- components/net/resource_task.rs | 7 +++++++ components/net_traits/lib.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 41b23a2eb82..6968da6a94f 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -366,6 +366,13 @@ impl ResourceChannelManager { ControlMsg::GetCookiesForUrl(url, consumer, source) => { consumer.send(self.resource_manager.cookie_storage.cookies_for_url(&url, source)).unwrap(); } + ControlMsg::SetHSTSEntryForHost(host, include_subdomains, max_age) => { + match HSTSEntry::new(host, include_subdomains, max_age) { + Some(entry) => self.resource_manager.add_hsts_entry(entry), + /// Invalid entries (e.g. IP's don't matter) + None => () + } + } ControlMsg::Exit => { break } diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 620d6c39aaf..5da6357d333 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -126,6 +126,8 @@ pub enum ControlMsg { SetCookiesForUrl(Url, String, CookieSource), /// Retrieve the stored cookies for a given URL GetCookiesForUrl(Url, Sender>, CookieSource), + /// Store a domain's STS information + SetHSTSEntryForHost(String, bool, Option), Exit } From 8a401d5a7f9151bd2d7968878580a9acd56e924b Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Thu, 25 Jun 2015 14:33:45 -0700 Subject: [PATCH 12/24] Re-parse URL to not have inconsistent state --- components/net/resource_task.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 6968da6a94f..f46e35057dc 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -308,7 +308,7 @@ pub fn secure_load_data(load_data: &LoadData) -> LoadData { let mut secure_load_data = load_data.clone(); let mut secure_url = load_data.url.clone(); secure_url.scheme = "https".to_string(); - secure_load_data.url = secure_url; + secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); secure_load_data }, From 865fb2eacb1abd3f8493b94f9c1f57e347f5427f Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Fri, 26 Jun 2015 16:47:32 -0700 Subject: [PATCH 13/24] Resolve tidy issues --- python/servo/bootstrap_commands.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python/servo/bootstrap_commands.py b/python/servo/bootstrap_commands.py index 67345fb1fdd..407addc31b3 100644 --- a/python/servo/bootstrap_commands.py +++ b/python/servo/bootstrap_commands.py @@ -47,7 +47,8 @@ def download(desc, src, writer): while True: chunk = resp.read(chunk_size) - if not chunk: break + if not chunk: + break recved += len(chunk) if not dumb: if fsize is not None: @@ -72,15 +73,18 @@ def download(desc, src, writer): sys.exit(1) + def download_file(desc, src, dst): with open(dst, 'wb') as fd: download(desc, src, fd) + def download_bytes(desc, src): content_writer = StringIO.StringIO() download(desc, src, content_writer) return content_writer.getvalue() + def extract(src, dst, movedir=None): tarfile.open(src).extractall(dst) @@ -218,7 +222,8 @@ class MachCommands(CommandBase): print("Use |bootstrap-hsts-preload --force| to download again.") return - chromium_hsts_url = "https://chromium.googlesource.com/chromium/src/net/+/master/http/transport_security_state_static.json?format=TEXT" + chromium_hsts_url = "https://chromium.googlesource.com/chromium/src" + \ + "/net/+/master/http/transport_security_state_static.json?format=TEXT" try: content_base64 = download_bytes("Chromium HSTS preload list", chromium_hsts_url) From a068a806190490dcf5830563dd0d15f3416b31f5 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Wed, 8 Jul 2015 18:26:10 +1200 Subject: [PATCH 14/24] Don't unnecessarily clone strings --- components/net/resource_task.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index f46e35057dc..9ee9bb4699c 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -267,21 +267,21 @@ impl HSTSList { }) } - fn has_domain(&self, host: String) -> bool { + fn has_domain(&self, host: &str) -> bool { self.entries.iter().any(|e| { e.matches_domain(&host) }) } - fn has_subdomain(&self, host: String) -> bool { + fn has_subdomain(&self, host: &str) -> bool { self.entries.iter().any(|e| { - e.matches_subdomain(&host) + e.matches_subdomain(host) }) } pub fn push(&mut self, entry: HSTSEntry) { - let have_domain = self.has_domain(entry.host.clone()); - let have_subdomain = self.has_subdomain(entry.host.clone()); + let have_domain = self.has_domain(&entry.host); + let have_subdomain = self.has_subdomain(&entry.host); if !have_domain && !have_subdomain { self.entries.push(entry); From 8086034e0b9ff93c262758c450865f12ca445649 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Wed, 8 Jul 2015 18:26:33 +1200 Subject: [PATCH 15/24] Commit HSTS preload list to source control * No longer download the HSTS list as a bootstrap step * Check the current revision of the HSTS list into source --- .gitignore | 1 - python/servo/bootstrap_commands.py | 14 +- python/servo/command_base.py | 2 - resources/hsts_preload.json | 11704 +++++++++++++++++++++++++++ 4 files changed, 11706 insertions(+), 15 deletions(-) create mode 100644 resources/hsts_preload.json diff --git a/.gitignore b/.gitignore index 0354c3e17f3..a21c4e30a17 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,3 @@ Servo.app .config.mk.last parser.out /glfw -hsts_preload.json diff --git a/python/servo/bootstrap_commands.py b/python/servo/bootstrap_commands.py index 407addc31b3..3eb501e2377 100644 --- a/python/servo/bootstrap_commands.py +++ b/python/servo/bootstrap_commands.py @@ -54,8 +54,6 @@ def download(desc, src, writer): if fsize is not None: pct = recved * 100.0 / fsize print("\rDownloading %s: %5.1f%%" % (desc, pct), end="") - else: - print("\rDownloading %s" % desc, end="") sys.stdout.flush() writer.write(chunk) @@ -207,27 +205,19 @@ class MachCommands(CommandBase): extract(tgz_file, cargo_dir, movedir=nightly_dir) print("Cargo ready.") - @Command('bootstrap-hsts-preload', + @Command('update-hsts-preload', description='Download the HSTS preload list', category='bootstrap') - @CommandArgument('--force', '-f', - action='store_true', - help='Force download even if HSTS list already exist') def bootstrap_hsts_preload(self, force=False): preload_filename = "hsts_preload.json" preload_path = path.join(self.context.topdir, "resources") - if not force and path.exists(path.join(preload_path, preload_filename)): - print("HSTS preload list already downloaded.", end=" ") - print("Use |bootstrap-hsts-preload --force| to download again.") - return - chromium_hsts_url = "https://chromium.googlesource.com/chromium/src" + \ "/net/+/master/http/transport_security_state_static.json?format=TEXT" try: content_base64 = download_bytes("Chromium HSTS preload list", chromium_hsts_url) - except URLError, e: + except urllib2.URLError, e: print("Unable to download chromium HSTS preload list, are you connected to the internet?") sys.exit(1) diff --git a/python/servo/command_base.py b/python/servo/command_base.py index b4ba795691f..7c41fa42196 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -324,7 +324,5 @@ class CommandBase(object): not path.exists(path.join( self.config["tools"]["cargo-root"], "cargo", "bin", "cargo")): Registrar.dispatch("bootstrap-cargo", context=self.context) - if not path.exists(path.join("resources", "hsts_preload.json")): - Registrar.dispatch("bootstrap-hsts-preload", context=self.context) self.context.bootstrapped = True diff --git a/resources/hsts_preload.json b/resources/hsts_preload.json new file mode 100644 index 00000000000..008be7f39a6 --- /dev/null +++ b/resources/hsts_preload.json @@ -0,0 +1,11704 @@ +{ + "entries": [ + { + "host": "pinningtest.appspot.com", + "include_subdomains": true + }, + { + "host": "google.com", + "include_subdomains": true + }, + { + "host": "wallet.google.com", + "include_subdomains": true + }, + { + "host": "checkout.google.com", + "include_subdomains": true + }, + { + "host": "chrome.google.com", + "include_subdomains": true + }, + { + "host": "docs.google.com", + "include_subdomains": true + }, + { + "host": "domains.google.com", + "include_subdomains": true + }, + { + "host": "sites.google.com", + "include_subdomains": true + }, + { + "host": "spreadsheets.google.com", + "include_subdomains": true + }, + { + "host": "appengine.google.com", + "include_subdomains": true + }, + { + "host": "encrypted.google.com", + "include_subdomains": true + }, + { + "host": "accounts.google.com", + "include_subdomains": true + }, + { + "host": "profiles.google.com", + "include_subdomains": true + }, + { + "host": "mail.google.com", + "include_subdomains": true + }, + { + "host": "mail-settings.google.com", + "include_subdomains": true + }, + { + "host": "inbox.google.com", + "include_subdomains": true + }, + { + "host": "talkgadget.google.com", + "include_subdomains": true + }, + { + "host": "talk.google.com", + "include_subdomains": true + }, + { + "host": "hostedtalkgadget.google.com", + "include_subdomains": true + }, + { + "host": "plus.google.com", + "include_subdomains": true + }, + { + "host": "plus.sandbox.google.com", + "include_subdomains": true + }, + { + "host": "script.google.com", + "include_subdomains": true + }, + { + "host": "hangouts.google.com", + "include_subdomains": true + }, + { + "host": "history.google.com", + "include_subdomains": true + }, + { + "host": "security.google.com", + "include_subdomains": true + }, + { + "host": "goto.google.com", + "include_subdomains": true + }, + { + "host": "cloud.google.com", + "include_subdomains": true + }, + { + "host": "glass.google.com", + "include_subdomains": true + }, + { + "host": "admin.google.com", + "include_subdomains": true + }, + { + "host": "login.corp.google.com", + "include_subdomains": true + }, + { + "host": "play.google.com", + "include_subdomains": true + }, + { + "host": "passwords.google.com", + "include_subdomains": true + }, + { + "host": "myaccount.google.com", + "include_subdomains": true + }, + { + "host": "contributor.google.com", + "include_subdomains": true + }, + { + "host": "google", + "include_subdomains": true + }, + { + "host": "gmail.com", + "include_subdomains": false + }, + { + "host": "googlemail.com", + "include_subdomains": false + }, + { + "host": "www.gmail.com", + "include_subdomains": false + }, + { + "host": "www.googlemail.com", + "include_subdomains": false + }, + { + "host": "chrome.com", + "include_subdomains": true + }, + { + "host": "market.android.com", + "include_subdomains": true + }, + { + "host": "ssl.google-analytics.com", + "include_subdomains": true + }, + { + "host": "drive.google.com", + "include_subdomains": true + }, + { + "host": "googleplex.com", + "include_subdomains": true + }, + { + "host": "groups.google.com", + "include_subdomains": true + }, + { + "host": "apis.google.com", + "include_subdomains": true + }, + { + "host": "chromiumcodereview.appspot.com", + "include_subdomains": true + }, + { + "host": "chrome-devtools-frontend.appspot.com", + "include_subdomains": true + }, + { + "host": "codereview.appspot.com", + "include_subdomains": true + }, + { + "host": "codereview.chromium.org", + "include_subdomains": true + }, + { + "host": "code.google.com", + "include_subdomains": true + }, + { + "host": "googlecode.com", + "include_subdomains": true + }, + { + "host": "dl.google.com", + "include_subdomains": true + }, + { + "host": "translate.googleapis.com", + "include_subdomains": true + }, + { + "host": "gvt2.com", + "include_subdomains": true + }, + { + "host": "gvt3.com", + "include_subdomains": true + }, + { + "host": "webfilings.appspot.com", + "include_subdomains": true + }, + { + "host": "webfilings-mirror-hrd.appspot.com", + "include_subdomains": true + }, + { + "host": "webfilings-eu.appspot.com", + "include_subdomains": true + }, + { + "host": "webfilings-eu-mirror.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-demo-eu.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-demo-hrd.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-pentest.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-trial-hrd.appspot.com", + "include_subdomains": true + }, + { + "host": "xbrlsuccess.appspot.com", + "include_subdomains": true + }, + { + "host": "w-spotlight.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-training-hrd.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-bigsky-master.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-staging-hr.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-training-master.appspot.com", + "include_subdomains": true + }, + { + "host": "wf-dogfood-hrd.appspot.com", + "include_subdomains": true + }, + { + "host": "chart.apis.google.com", + "include_subdomains": true + }, + { + "host": "blogger.com", + "include_subdomains": true + }, + { + "host": "google-analytics.com", + "include_subdomains": true + }, + { + "host": "googlegroups.com", + "include_subdomains": true + }, + { + "host": "ytimg.com", + "include_subdomains": true + }, + { + "host": "googleusercontent.com", + "include_subdomains": true + }, + { + "host": "youtube.com", + "include_subdomains": true + }, + { + "host": "youtube-nocookie.com", + "include_subdomains": true + }, + { + "host": "googleapis.com", + "include_subdomains": true + }, + { + "host": "googleadservices.com", + "include_subdomains": true + }, + { + "host": "appspot.com", + "include_subdomains": true + }, + { + "host": "googlesyndication.com", + "include_subdomains": true + }, + { + "host": "doubleclick.net", + "include_subdomains": true + }, + { + "host": "2mdn.net", + "include_subdomains": true + }, + { + "host": "gstatic.com", + "include_subdomains": true + }, + { + "host": "youtu.be", + "include_subdomains": true + }, + { + "host": "android.com", + "include_subdomains": true + }, + { + "host": "googlecommerce.com", + "include_subdomains": true + }, + { + "host": "urchin.com", + "include_subdomains": true + }, + { + "host": "goo.gl", + "include_subdomains": true + }, + { + "host": "g.co", + "include_subdomains": true + }, + { + "host": "googletagmanager.com", + "include_subdomains": true + }, + { + "host": "googletagservices.com", + "include_subdomains": true + }, + { + "host": "google.ac", + "include_subdomains": true + }, + { + "host": "google.ad", + "include_subdomains": true + }, + { + "host": "google.ae", + "include_subdomains": true + }, + { + "host": "google.af", + "include_subdomains": true + }, + { + "host": "google.ag", + "include_subdomains": true + }, + { + "host": "google.am", + "include_subdomains": true + }, + { + "host": "google.as", + "include_subdomains": true + }, + { + "host": "google.at", + "include_subdomains": true + }, + { + "host": "google.az", + "include_subdomains": true + }, + { + "host": "google.ba", + "include_subdomains": true + }, + { + "host": "google.be", + "include_subdomains": true + }, + { + "host": "google.bf", + "include_subdomains": true + }, + { + "host": "google.bg", + "include_subdomains": true + }, + { + "host": "google.bi", + "include_subdomains": true + }, + { + "host": "google.bj", + "include_subdomains": true + }, + { + "host": "google.bs", + "include_subdomains": true + }, + { + "host": "google.by", + "include_subdomains": true + }, + { + "host": "google.ca", + "include_subdomains": true + }, + { + "host": "google.cat", + "include_subdomains": true + }, + { + "host": "google.cc", + "include_subdomains": true + }, + { + "host": "google.cd", + "include_subdomains": true + }, + { + "host": "google.cf", + "include_subdomains": true + }, + { + "host": "google.cg", + "include_subdomains": true + }, + { + "host": "google.ch", + "include_subdomains": true + }, + { + "host": "google.ci", + "include_subdomains": true + }, + { + "host": "google.cl", + "include_subdomains": true + }, + { + "host": "google.cm", + "include_subdomains": true + }, + { + "host": "google.cn", + "include_subdomains": true + }, + { + "host": "google.co.ao", + "include_subdomains": true + }, + { + "host": "google.co.bw", + "include_subdomains": true + }, + { + "host": "google.co.ck", + "include_subdomains": true + }, + { + "host": "google.co.cr", + "include_subdomains": true + }, + { + "host": "google.co.hu", + "include_subdomains": true + }, + { + "host": "google.co.id", + "include_subdomains": true + }, + { + "host": "google.co.il", + "include_subdomains": true + }, + { + "host": "google.co.im", + "include_subdomains": true + }, + { + "host": "google.co.in", + "include_subdomains": true + }, + { + "host": "google.co.je", + "include_subdomains": true + }, + { + "host": "google.co.jp", + "include_subdomains": true + }, + { + "host": "google.co.ke", + "include_subdomains": true + }, + { + "host": "google.co.kr", + "include_subdomains": true + }, + { + "host": "google.co.ls", + "include_subdomains": true + }, + { + "host": "google.co.ma", + "include_subdomains": true + }, + { + "host": "google.co.mz", + "include_subdomains": true + }, + { + "host": "google.co.nz", + "include_subdomains": true + }, + { + "host": "google.co.th", + "include_subdomains": true + }, + { + "host": "google.co.tz", + "include_subdomains": true + }, + { + "host": "google.co.ug", + "include_subdomains": true + }, + { + "host": "google.co.uk", + "include_subdomains": true + }, + { + "host": "google.co.uz", + "include_subdomains": true + }, + { + "host": "google.co.ve", + "include_subdomains": true + }, + { + "host": "google.co.vi", + "include_subdomains": true + }, + { + "host": "google.co.za", + "include_subdomains": true + }, + { + "host": "google.co.zm", + "include_subdomains": true + }, + { + "host": "google.co.zw", + "include_subdomains": true + }, + { + "host": "google.com.af", + "include_subdomains": true + }, + { + "host": "google.com.ag", + "include_subdomains": true + }, + { + "host": "google.com.ai", + "include_subdomains": true + }, + { + "host": "google.com.ar", + "include_subdomains": true + }, + { + "host": "google.com.au", + "include_subdomains": true + }, + { + "host": "google.com.bd", + "include_subdomains": true + }, + { + "host": "google.com.bh", + "include_subdomains": true + }, + { + "host": "google.com.bn", + "include_subdomains": true + }, + { + "host": "google.com.bo", + "include_subdomains": true + }, + { + "host": "google.com.br", + "include_subdomains": true + }, + { + "host": "google.com.by", + "include_subdomains": true + }, + { + "host": "google.com.bz", + "include_subdomains": true + }, + { + "host": "google.com.cn", + "include_subdomains": true + }, + { + "host": "google.com.co", + "include_subdomains": true + }, + { + "host": "google.com.cu", + "include_subdomains": true + }, + { + "host": "google.com.cy", + "include_subdomains": true + }, + { + "host": "google.com.do", + "include_subdomains": true + }, + { + "host": "google.com.ec", + "include_subdomains": true + }, + { + "host": "google.com.eg", + "include_subdomains": true + }, + { + "host": "google.com.et", + "include_subdomains": true + }, + { + "host": "google.com.fj", + "include_subdomains": true + }, + { + "host": "google.com.ge", + "include_subdomains": true + }, + { + "host": "google.com.gh", + "include_subdomains": true + }, + { + "host": "google.com.gi", + "include_subdomains": true + }, + { + "host": "google.com.gr", + "include_subdomains": true + }, + { + "host": "google.com.gt", + "include_subdomains": true + }, + { + "host": "google.com.hk", + "include_subdomains": true + }, + { + "host": "google.com.iq", + "include_subdomains": true + }, + { + "host": "google.com.jm", + "include_subdomains": true + }, + { + "host": "google.com.jo", + "include_subdomains": true + }, + { + "host": "google.com.kh", + "include_subdomains": true + }, + { + "host": "google.com.kw", + "include_subdomains": true + }, + { + "host": "google.com.lb", + "include_subdomains": true + }, + { + "host": "google.com.ly", + "include_subdomains": true + }, + { + "host": "google.com.mt", + "include_subdomains": true + }, + { + "host": "google.com.mx", + "include_subdomains": true + }, + { + "host": "google.com.my", + "include_subdomains": true + }, + { + "host": "google.com.na", + "include_subdomains": true + }, + { + "host": "google.com.nf", + "include_subdomains": true + }, + { + "host": "google.com.ng", + "include_subdomains": true + }, + { + "host": "google.com.ni", + "include_subdomains": true + }, + { + "host": "google.com.np", + "include_subdomains": true + }, + { + "host": "google.com.nr", + "include_subdomains": true + }, + { + "host": "google.com.om", + "include_subdomains": true + }, + { + "host": "google.com.pa", + "include_subdomains": true + }, + { + "host": "google.com.pe", + "include_subdomains": true + }, + { + "host": "google.com.ph", + "include_subdomains": true + }, + { + "host": "google.com.pk", + "include_subdomains": true + }, + { + "host": "google.com.pl", + "include_subdomains": true + }, + { + "host": "google.com.pr", + "include_subdomains": true + }, + { + "host": "google.com.py", + "include_subdomains": true + }, + { + "host": "google.com.qa", + "include_subdomains": true + }, + { + "host": "google.com.ru", + "include_subdomains": true + }, + { + "host": "google.com.sa", + "include_subdomains": true + }, + { + "host": "google.com.sb", + "include_subdomains": true + }, + { + "host": "google.com.sg", + "include_subdomains": true + }, + { + "host": "google.com.sl", + "include_subdomains": true + }, + { + "host": "google.com.sv", + "include_subdomains": true + }, + { + "host": "google.com.tj", + "include_subdomains": true + }, + { + "host": "google.com.tn", + "include_subdomains": true + }, + { + "host": "google.com.tr", + "include_subdomains": true + }, + { + "host": "google.com.tw", + "include_subdomains": true + }, + { + "host": "google.com.ua", + "include_subdomains": true + }, + { + "host": "google.com.uy", + "include_subdomains": true + }, + { + "host": "google.com.vc", + "include_subdomains": true + }, + { + "host": "google.com.ve", + "include_subdomains": true + }, + { + "host": "google.com.vn", + "include_subdomains": true + }, + { + "host": "google.cv", + "include_subdomains": true + }, + { + "host": "google.cz", + "include_subdomains": true + }, + { + "host": "google.de", + "include_subdomains": true + }, + { + "host": "google.dj", + "include_subdomains": true + }, + { + "host": "google.dk", + "include_subdomains": true + }, + { + "host": "google.dm", + "include_subdomains": true + }, + { + "host": "google.dz", + "include_subdomains": true + }, + { + "host": "google.ee", + "include_subdomains": true + }, + { + "host": "google.es", + "include_subdomains": true + }, + { + "host": "google.fi", + "include_subdomains": true + }, + { + "host": "google.fm", + "include_subdomains": true + }, + { + "host": "google.fr", + "include_subdomains": true + }, + { + "host": "google.ga", + "include_subdomains": true + }, + { + "host": "google.ge", + "include_subdomains": true + }, + { + "host": "google.gg", + "include_subdomains": true + }, + { + "host": "google.gl", + "include_subdomains": true + }, + { + "host": "google.gm", + "include_subdomains": true + }, + { + "host": "google.gp", + "include_subdomains": true + }, + { + "host": "google.gr", + "include_subdomains": true + }, + { + "host": "google.gy", + "include_subdomains": true + }, + { + "host": "google.hk", + "include_subdomains": true + }, + { + "host": "google.hn", + "include_subdomains": true + }, + { + "host": "google.hr", + "include_subdomains": true + }, + { + "host": "google.ht", + "include_subdomains": true + }, + { + "host": "google.hu", + "include_subdomains": true + }, + { + "host": "google.ie", + "include_subdomains": true + }, + { + "host": "google.im", + "include_subdomains": true + }, + { + "host": "google.info", + "include_subdomains": true + }, + { + "host": "google.iq", + "include_subdomains": true + }, + { + "host": "google.is", + "include_subdomains": true + }, + { + "host": "google.it", + "include_subdomains": true + }, + { + "host": "google.it.ao", + "include_subdomains": true + }, + { + "host": "google.je", + "include_subdomains": true + }, + { + "host": "google.jo", + "include_subdomains": true + }, + { + "host": "google.jobs", + "include_subdomains": true + }, + { + "host": "google.jp", + "include_subdomains": true + }, + { + "host": "google.kg", + "include_subdomains": true + }, + { + "host": "google.ki", + "include_subdomains": true + }, + { + "host": "google.kz", + "include_subdomains": true + }, + { + "host": "google.la", + "include_subdomains": true + }, + { + "host": "google.li", + "include_subdomains": true + }, + { + "host": "google.lk", + "include_subdomains": true + }, + { + "host": "google.lt", + "include_subdomains": true + }, + { + "host": "google.lu", + "include_subdomains": true + }, + { + "host": "google.lv", + "include_subdomains": true + }, + { + "host": "google.md", + "include_subdomains": true + }, + { + "host": "google.me", + "include_subdomains": true + }, + { + "host": "google.mg", + "include_subdomains": true + }, + { + "host": "google.mk", + "include_subdomains": true + }, + { + "host": "google.ml", + "include_subdomains": true + }, + { + "host": "google.mn", + "include_subdomains": true + }, + { + "host": "google.ms", + "include_subdomains": true + }, + { + "host": "google.mu", + "include_subdomains": true + }, + { + "host": "google.mv", + "include_subdomains": true + }, + { + "host": "google.mw", + "include_subdomains": true + }, + { + "host": "google.ne", + "include_subdomains": true + }, + { + "host": "google.ne.jp", + "include_subdomains": true + }, + { + "host": "google.net", + "include_subdomains": true + }, + { + "host": "google.nl", + "include_subdomains": true + }, + { + "host": "google.no", + "include_subdomains": true + }, + { + "host": "google.nr", + "include_subdomains": true + }, + { + "host": "google.nu", + "include_subdomains": true + }, + { + "host": "google.off.ai", + "include_subdomains": true + }, + { + "host": "google.pk", + "include_subdomains": true + }, + { + "host": "google.pl", + "include_subdomains": true + }, + { + "host": "google.pn", + "include_subdomains": true + }, + { + "host": "google.ps", + "include_subdomains": true + }, + { + "host": "google.pt", + "include_subdomains": true + }, + { + "host": "google.ro", + "include_subdomains": true + }, + { + "host": "google.rs", + "include_subdomains": true + }, + { + "host": "google.ru", + "include_subdomains": true + }, + { + "host": "google.rw", + "include_subdomains": true + }, + { + "host": "google.sc", + "include_subdomains": true + }, + { + "host": "google.se", + "include_subdomains": true + }, + { + "host": "google.sh", + "include_subdomains": true + }, + { + "host": "google.si", + "include_subdomains": true + }, + { + "host": "google.sk", + "include_subdomains": true + }, + { + "host": "google.sm", + "include_subdomains": true + }, + { + "host": "google.sn", + "include_subdomains": true + }, + { + "host": "google.so", + "include_subdomains": true + }, + { + "host": "google.st", + "include_subdomains": true + }, + { + "host": "google.td", + "include_subdomains": true + }, + { + "host": "google.tg", + "include_subdomains": true + }, + { + "host": "google.tk", + "include_subdomains": true + }, + { + "host": "google.tl", + "include_subdomains": true + }, + { + "host": "google.tm", + "include_subdomains": true + }, + { + "host": "google.tn", + "include_subdomains": true + }, + { + "host": "google.to", + "include_subdomains": true + }, + { + "host": "google.tt", + "include_subdomains": true + }, + { + "host": "google.us", + "include_subdomains": true + }, + { + "host": "google.uz", + "include_subdomains": true + }, + { + "host": "google.vg", + "include_subdomains": true + }, + { + "host": "google.vu", + "include_subdomains": true + }, + { + "host": "google.ws", + "include_subdomains": true + }, + { + "host": "learn.doubleclick.net", + "include_subdomains": true + }, + { + "host": "www.paypal.com", + "include_subdomains": false + }, + { + "host": "paypal.com", + "include_subdomains": false + }, + { + "host": "www.elanex.biz", + "include_subdomains": false + }, + { + "host": "jottit.com", + "include_subdomains": true + }, + { + "host": "sunshinepress.org", + "include_subdomains": true + }, + { + "host": "www.noisebridge.net", + "include_subdomains": false + }, + { + "host": "neg9.org", + "include_subdomains": false + }, + { + "host": "riseup.net", + "include_subdomains": true + }, + { + "host": "factor.cc", + "include_subdomains": false + }, + { + "host": "members.mayfirst.org", + "include_subdomains": true + }, + { + "host": "support.mayfirst.org", + "include_subdomains": true + }, + { + "host": "id.mayfirst.org", + "include_subdomains": true + }, + { + "host": "lists.mayfirst.org", + "include_subdomains": true + }, + { + "host": "webmail.mayfirst.org", + "include_subdomains": true + }, + { + "host": "roundcube.mayfirst.org", + "include_subdomains": true + }, + { + "host": "aladdinschools.appspot.com", + "include_subdomains": false + }, + { + "host": "ottospora.nl", + "include_subdomains": true + }, + { + "host": "www.paycheckrecords.com", + "include_subdomains": false + }, + { + "host": "lastpass.com", + "include_subdomains": false + }, + { + "host": "www.lastpass.com", + "include_subdomains": false + }, + { + "host": "keyerror.com", + "include_subdomains": true + }, + { + "host": "entropia.de", + "include_subdomains": false + }, + { + "host": "www.entropia.de", + "include_subdomains": false + }, + { + "host": "romab.com", + "include_subdomains": true + }, + { + "host": "logentries.com", + "include_subdomains": false + }, + { + "host": "www.logentries.com", + "include_subdomains": false + }, + { + "host": "stripe.com", + "include_subdomains": true + }, + { + "host": "cloudsecurityalliance.org", + "include_subdomains": true + }, + { + "host": "login.sapo.pt", + "include_subdomains": true + }, + { + "host": "mattmccutchen.net", + "include_subdomains": true + }, + { + "host": "betnet.fr", + "include_subdomains": true + }, + { + "host": "uprotect.it", + "include_subdomains": true + }, + { + "host": "squareup.com", + "include_subdomains": false + }, + { + "host": "square.com", + "include_subdomains": true + }, + { + "host": "cert.se", + "include_subdomains": true + }, + { + "host": "crypto.is", + "include_subdomains": true + }, + { + "host": "simon.butcher.name", + "include_subdomains": true + }, + { + "host": "linx.net", + "include_subdomains": true + }, + { + "host": "dropcam.com", + "include_subdomains": false + }, + { + "host": "www.dropcam.com", + "include_subdomains": false + }, + { + "host": "ebanking.indovinabank.com.vn", + "include_subdomains": true + }, + { + "host": "epoxate.com", + "include_subdomains": false + }, + { + "host": "torproject.org", + "include_subdomains": false + }, + { + "host": "blog.torproject.org", + "include_subdomains": true + }, + { + "host": "check.torproject.org", + "include_subdomains": true + }, + { + "host": "www.torproject.org", + "include_subdomains": true + }, + { + "host": "dist.torproject.org", + "include_subdomains": true + }, + { + "host": "www.moneybookers.com", + "include_subdomains": true + }, + { + "host": "ledgerscope.net", + "include_subdomains": false + }, + { + "host": "www.ledgerscope.net", + "include_subdomains": false + }, + { + "host": "app.recurly.com", + "include_subdomains": true + }, + { + "host": "api.recurly.com", + "include_subdomains": true + }, + { + "host": "greplin.com", + "include_subdomains": false + }, + { + "host": "www.greplin.com", + "include_subdomains": false + }, + { + "host": "luneta.nearbuysystems.com", + "include_subdomains": true + }, + { + "host": "ubertt.org", + "include_subdomains": true + }, + { + "host": "pixi.me", + "include_subdomains": true + }, + { + "host": "grepular.com", + "include_subdomains": true + }, + { + "host": "mydigipass.com", + "include_subdomains": false + }, + { + "host": "www.mydigipass.com", + "include_subdomains": false + }, + { + "host": "developer.mydigipass.com", + "include_subdomains": false + }, + { + "host": "www.developer.mydigipass.com", + "include_subdomains": false + }, + { + "host": "sandbox.mydigipass.com", + "include_subdomains": false + }, + { + "host": "www.sandbox.mydigipass.com", + "include_subdomains": false + }, + { + "host": "crypto.cat", + "include_subdomains": false + }, + { + "host": "bigshinylock.minazo.net", + "include_subdomains": true + }, + { + "host": "crate.io", + "include_subdomains": true + }, + { + "host": "twitter.com", + "include_subdomains": false + }, + { + "host": "www.twitter.com", + "include_subdomains": true + }, + { + "host": "api.twitter.com", + "include_subdomains": true + }, + { + "host": "oauth.twitter.com", + "include_subdomains": true + }, + { + "host": "mobile.twitter.com", + "include_subdomains": true + }, + { + "host": "dev.twitter.com", + "include_subdomains": true + }, + { + "host": "business.twitter.com", + "include_subdomains": true + }, + { + "host": "platform.twitter.com", + "include_subdomains": true + }, + { + "host": "twimg.com", + "include_subdomains": true + }, + { + "host": "braintreegateway.com", + "include_subdomains": true + }, + { + "host": "braintreepayments.com", + "include_subdomains": false + }, + { + "host": "www.braintreepayments.com", + "include_subdomains": false + }, + { + "host": "emailprivacytester.com", + "include_subdomains": false + }, + { + "host": "tor2web.org", + "include_subdomains": true + }, + { + "host": "business.medbank.com.mt", + "include_subdomains": true + }, + { + "host": "arivo.com.br", + "include_subdomains": true + }, + { + "host": "www.apollo-auto.com", + "include_subdomains": true + }, + { + "host": "www.cueup.com", + "include_subdomains": true + }, + { + "host": "jitsi.org", + "include_subdomains": false + }, + { + "host": "www.jitsi.org", + "include_subdomains": false + }, + { + "host": "download.jitsi.org", + "include_subdomains": false + }, + { + "host": "sol.io", + "include_subdomains": true + }, + { + "host": "irccloud.com", + "include_subdomains": false + }, + { + "host": "www.irccloud.com", + "include_subdomains": false + }, + { + "host": "alpha.irccloud.com", + "include_subdomains": false + }, + { + "host": "passwd.io", + "include_subdomains": true + }, + { + "host": "browserid.org", + "include_subdomains": true + }, + { + "host": "login.persona.org", + "include_subdomains": true + }, + { + "host": "neonisi.com", + "include_subdomains": false + }, + { + "host": "www.neonisi.com", + "include_subdomains": true + }, + { + "host": "shops.neonisi.com", + "include_subdomains": true + }, + { + "host": "piratenlogin.de", + "include_subdomains": true + }, + { + "host": "howrandom.org", + "include_subdomains": true + }, + { + "host": "intercom.io", + "include_subdomains": false + }, + { + "host": "api.intercom.io", + "include_subdomains": false + }, + { + "host": "www.intercom.io", + "include_subdomains": false + }, + { + "host": "fatzebra.com.au", + "include_subdomains": true + }, + { + "host": "csawctf.poly.edu", + "include_subdomains": true + }, + { + "host": "makeyourlaws.org", + "include_subdomains": true + }, + { + "host": "www.makeyourlaws.org", + "include_subdomains": false + }, + { + "host": "iop.intuit.com", + "include_subdomains": true + }, + { + "host": "surfeasy.com", + "include_subdomains": false + }, + { + "host": "www.surfeasy.com", + "include_subdomains": false + }, + { + "host": "packagist.org", + "include_subdomains": false + }, + { + "host": "lookout.com", + "include_subdomains": false + }, + { + "host": "www.lookout.com", + "include_subdomains": false + }, + { + "host": "mylookout.com", + "include_subdomains": false + }, + { + "host": "www.mylookout.com", + "include_subdomains": false + }, + { + "host": "dm.lookout.com", + "include_subdomains": true + }, + { + "host": "business.lookout.com", + "include_subdomains": true + }, + { + "host": "blog.lookout.com", + "include_subdomains": true + }, + { + "host": "faq.lookout.com", + "include_subdomains": true + }, + { + "host": "platform.lookout.com", + "include_subdomains": true + }, + { + "host": "email.lookout.com", + "include_subdomains": true + }, + { + "host": "app.lookout.com", + "include_subdomains": true + }, + { + "host": "api.lookout.com", + "include_subdomains": true + }, + { + "host": "keymaster.lookout.com", + "include_subdomains": true + }, + { + "host": "mygadgetguardian.lookout.com", + "include_subdomains": true + }, + { + "host": "discovery.lookout.com", + "include_subdomains": true + }, + { + "host": "mobilethreat.net", + "include_subdomains": true + }, + { + "host": "mobilethreatnetwork.net", + "include_subdomains": true + }, + { + "host": "itriskltd.com", + "include_subdomains": true + }, + { + "host": "stocktrade.de", + "include_subdomains": true + }, + { + "host": "openshift.redhat.com", + "include_subdomains": true + }, + { + "host": "therapynotes.com", + "include_subdomains": false + }, + { + "host": "www.therapynotes.com", + "include_subdomains": false + }, + { + "host": "wiz.biz", + "include_subdomains": true + }, + { + "host": "my.onlime.ch", + "include_subdomains": true + }, + { + "host": "webmail.onlime.ch", + "include_subdomains": true + }, + { + "host": "crm.onlime.ch", + "include_subdomains": true + }, + { + "host": "www.gov.uk", + "include_subdomains": true + }, + { + "host": "silentcircle.com", + "include_subdomains": true + }, + { + "host": "silentcircle.org", + "include_subdomains": true + }, + { + "host": "serverdensity.io", + "include_subdomains": true + }, + { + "host": "my.alfresco.com", + "include_subdomains": true + }, + { + "host": "webmail.gigahost.dk", + "include_subdomains": true + }, + { + "host": "paymill.com", + "include_subdomains": true + }, + { + "host": "paymill.de", + "include_subdomains": true + }, + { + "host": "gocardless.com", + "include_subdomains": true + }, + { + "host": "espra.com", + "include_subdomains": true + }, + { + "host": "zoo24.de", + "include_subdomains": true + }, + { + "host": "mega.co.nz", + "include_subdomains": false + }, + { + "host": "api.mega.co.nz", + "include_subdomains": true + }, + { + "host": "lockify.com", + "include_subdomains": true + }, + { + "host": "writeapp.me", + "include_subdomains": false + }, + { + "host": "bugzilla.mozilla.org", + "include_subdomains": true + }, + { + "host": "members.nearlyfreespeech.net", + "include_subdomains": true + }, + { + "host": "ssl.panoramio.com", + "include_subdomains": false + }, + { + "host": "kiwiirc.com", + "include_subdomains": false + }, + { + "host": "pay.gigahost.dk", + "include_subdomains": true + }, + { + "host": "controlcenter.gigahost.dk", + "include_subdomains": true + }, + { + "host": "simple.com", + "include_subdomains": false + }, + { + "host": "www.simple.com", + "include_subdomains": false + }, + { + "host": "fj.simple.com", + "include_subdomains": false + }, + { + "host": "api.simple.com", + "include_subdomains": false + }, + { + "host": "bank.simple.com", + "include_subdomains": true + }, + { + "host": "bassh.net", + "include_subdomains": true + }, + { + "host": "sah3.net", + "include_subdomains": true + }, + { + "host": "grc.com", + "include_subdomains": false + }, + { + "host": "www.grc.com", + "include_subdomains": false + }, + { + "host": "linode.com", + "include_subdomains": false + }, + { + "host": "www.linode.com", + "include_subdomains": false + }, + { + "host": "manager.linode.com", + "include_subdomains": false + }, + { + "host": "blog.linode.com", + "include_subdomains": false + }, + { + "host": "library.linode.com", + "include_subdomains": false + }, + { + "host": "forum.linode.com", + "include_subdomains": false + }, + { + "host": "p.linode.com", + "include_subdomains": false + }, + { + "host": "paste.linode.com", + "include_subdomains": false + }, + { + "host": "pastebin.linode.com", + "include_subdomains": false + }, + { + "host": "inertianetworks.com", + "include_subdomains": true + }, + { + "host": "carezone.com", + "include_subdomains": false + }, + { + "host": "conformal.com", + "include_subdomains": true + }, + { + "host": "cyphertite.com", + "include_subdomains": true + }, + { + "host": "logotype.se", + "include_subdomains": true + }, + { + "host": "bccx.com", + "include_subdomains": true + }, + { + "host": "launchkey.com", + "include_subdomains": true + }, + { + "host": "carlolly.co.uk", + "include_subdomains": true + }, + { + "host": "www.cyveillance.com", + "include_subdomains": true + }, + { + "host": "blog.cyveillance.com", + "include_subdomains": true + }, + { + "host": "whonix.org", + "include_subdomains": true + }, + { + "host": "shodan.io", + "include_subdomains": true + }, + { + "host": "rapidresearch.me", + "include_subdomains": true + }, + { + "host": "surkatty.org", + "include_subdomains": true + }, + { + "host": "securityheaders.com", + "include_subdomains": true + }, + { + "host": "haste.ch", + "include_subdomains": true + }, + { + "host": "mudcrab.us", + "include_subdomains": true + }, + { + "host": "mediacru.sh", + "include_subdomains": true + }, + { + "host": "lolicore.ch", + "include_subdomains": true + }, + { + "host": "cloudns.com.au", + "include_subdomains": true + }, + { + "host": "oplop.appspot.com", + "include_subdomains": true + }, + { + "host": "bcrook.com", + "include_subdomains": false + }, + { + "host": "wiki.python.org", + "include_subdomains": true + }, + { + "host": "lumi.do", + "include_subdomains": false + }, + { + "host": "appseccalifornia.org", + "include_subdomains": true + }, + { + "host": "crowdcurity.com", + "include_subdomains": true + }, + { + "host": "saturngames.co.uk", + "include_subdomains": true + }, + { + "host": "strongest-privacy.com", + "include_subdomains": true + }, + { + "host": "ecosystem.atlassian.net", + "include_subdomains": true + }, + { + "host": "id.atlassian.com", + "include_subdomains": true + }, + { + "host": "bitbucket.org", + "include_subdomains": false + }, + { + "host": "cupcake.io", + "include_subdomains": true + }, + { + "host": "cupcake.is", + "include_subdomains": true + }, + { + "host": "tent.io", + "include_subdomains": true + }, + { + "host": "cybozu.com", + "include_subdomains": true + }, + { + "host": "davidlyness.com", + "include_subdomains": true + }, + { + "host": "medium.com", + "include_subdomains": true + }, + { + "host": "getlantern.org", + "include_subdomains": true + }, + { + "host": "kinsights.com", + "include_subdomains": false + }, + { + "host": "simbolo.co.uk", + "include_subdomains": false + }, + { + "host": "www.simbolo.co.uk", + "include_subdomains": false + }, + { + "host": "zenpayroll.com", + "include_subdomains": false + }, + { + "host": "www.zenpayroll.com", + "include_subdomains": false + }, + { + "host": "get.zenpayroll.com", + "include_subdomains": false + }, + { + "host": "errors.zenpayroll.com", + "include_subdomains": false + }, + { + "host": "manage.zenpayroll.com", + "include_subdomains": false + }, + { + "host": "gernert-server.de", + "include_subdomains": true + }, + { + "host": "skydrive.live.com", + "include_subdomains": true + }, + { + "host": "lifeguard.aecom.com", + "include_subdomains": true + }, + { + "host": "data.qld.gov.au", + "include_subdomains": false + }, + { + "host": "publications.qld.gov.au", + "include_subdomains": false + }, + { + "host": "go.xero.com", + "include_subdomains": true + }, + { + "host": "login.xero.com", + "include_subdomains": true + }, + { + "host": "my.xero.com", + "include_subdomains": true + }, + { + "host": "payroll.xero.com", + "include_subdomains": true + }, + { + "host": "in.xero.com", + "include_subdomains": true + }, + { + "host": "api.xero.com", + "include_subdomains": true + }, + { + "host": "eff.org", + "include_subdomains": true + }, + { + "host": "mail.de", + "include_subdomains": true + }, + { + "host": "passport.yandex.ru", + "include_subdomains": false + }, + { + "host": "passport.yandex.com", + "include_subdomains": false + }, + { + "host": "passport.yandex.ua", + "include_subdomains": false + }, + { + "host": "passport.yandex.by", + "include_subdomains": false + }, + { + "host": "passport.yandex.kz", + "include_subdomains": false + }, + { + "host": "passport.yandex.com.tr", + "include_subdomains": false + }, + { + "host": "mnsure.org", + "include_subdomains": true + }, + { + "host": "getcloak.com", + "include_subdomains": false + }, + { + "host": "www.getcloak.com", + "include_subdomains": false + }, + { + "host": "www.heliosnet.com", + "include_subdomains": true + }, + { + "host": "opsmate.com", + "include_subdomains": false + }, + { + "host": "www.opsmate.com", + "include_subdomains": true + }, + { + "host": "f-droid.org", + "include_subdomains": true + }, + { + "host": "www.evernote.com", + "include_subdomains": false + }, + { + "host": "app.yinxiang.com", + "include_subdomains": false + }, + { + "host": "neilwynne.com", + "include_subdomains": false + }, + { + "host": "calyxinstitute.org", + "include_subdomains": false + }, + { + "host": "www.calyxinstitute.org", + "include_subdomains": false + }, + { + "host": "blacklane.com", + "include_subdomains": true + }, + { + "host": "boxcryptor.com", + "include_subdomains": true + }, + { + "host": "aclu.org", + "include_subdomains": false + }, + { + "host": "www.aclu.org", + "include_subdomains": false + }, + { + "host": "prodpad.com", + "include_subdomains": true + }, + { + "host": "mailbox.org", + "include_subdomains": true + }, + { + "host": "roddis.net", + "include_subdomains": true + }, + { + "host": "fiken.no", + "include_subdomains": true + }, + { + "host": "fairbill.com", + "include_subdomains": true + }, + { + "host": "nexth.net", + "include_subdomains": true + }, + { + "host": "nexth.us", + "include_subdomains": true + }, + { + "host": "nexth.de", + "include_subdomains": true + }, + { + "host": "souyar.net", + "include_subdomains": true + }, + { + "host": "souyar.de", + "include_subdomains": true + }, + { + "host": "souyar.us", + "include_subdomains": true + }, + { + "host": "www.banking.co.at", + "include_subdomains": false + }, + { + "host": "mbp.banking.co.at", + "include_subdomains": false + }, + { + "host": "feedbin.com", + "include_subdomains": false + }, + { + "host": "heha.co", + "include_subdomains": true + }, + { + "host": "passwordbox.com", + "include_subdomains": true + }, + { + "host": "python.org", + "include_subdomains": false + }, + { + "host": "pypi.python.org", + "include_subdomains": true + }, + { + "host": "www.python.org", + "include_subdomains": true + }, + { + "host": "docs.python.org", + "include_subdomains": true + }, + { + "host": "encircleapp.com", + "include_subdomains": true + }, + { + "host": "onedrive.live.com", + "include_subdomains": true + }, + { + "host": "onedrive.com", + "include_subdomains": true + }, + { + "host": "keepersecurity.com", + "include_subdomains": true + }, + { + "host": "keeperapp.com", + "include_subdomains": true + }, + { + "host": "donmez.ws", + "include_subdomains": true + }, + { + "host": "activiti.alfresco.com", + "include_subdomains": false + }, + { + "host": "cloudcert.org", + "include_subdomains": true + }, + { + "host": "seifried.org", + "include_subdomains": true + }, + { + "host": "wepay.com", + "include_subdomains": false + }, + { + "host": "www.wepay.com", + "include_subdomains": false + }, + { + "host": "static.wepay.com", + "include_subdomains": false + }, + { + "host": "stage.wepay.com", + "include_subdomains": false + }, + { + "host": "vmoagents.com", + "include_subdomains": false + }, + { + "host": "adsfund.org", + "include_subdomains": true + }, + { + "host": "pult.co", + "include_subdomains": false + }, + { + "host": "dillonkorman.com", + "include_subdomains": true + }, + { + "host": "edmodo.com", + "include_subdomains": true + }, + { + "host": "www.eternalgoth.co.uk", + "include_subdomains": false + }, + { + "host": "app.manilla.com", + "include_subdomains": true + }, + { + "host": "harvestapp.com", + "include_subdomains": true + }, + { + "host": "anycoin.me", + "include_subdomains": true + }, + { + "host": "noexpect.org", + "include_subdomains": true + }, + { + "host": "airbnb.com", + "include_subdomains": false + }, + { + "host": "www.airbnb.com", + "include_subdomains": true + }, + { + "host": "usaa.com", + "include_subdomains": false + }, + { + "host": "www.usaa.com", + "include_subdomains": false + }, + { + "host": "mobile.usaa.com", + "include_subdomains": false + }, + { + "host": "subrosa.io", + "include_subdomains": true + }, + { + "host": "detectify.com", + "include_subdomains": false + }, + { + "host": "crbug.com", + "include_subdomains": true + }, + { + "host": "manageprojects.com", + "include_subdomains": true + }, + { + "host": "tinfoilsecurity.com", + "include_subdomains": false + }, + { + "host": "www.tinfoilsecurity.com", + "include_subdomains": false + }, + { + "host": "imouto.my", + "include_subdomains": false + }, + { + "host": "vocaloid.my", + "include_subdomains": true + }, + { + "host": "sakaki.anime.my", + "include_subdomains": true + }, + { + "host": "reviews.anime.my", + "include_subdomains": true + }, + { + "host": "miku.hatsune.my", + "include_subdomains": true + }, + { + "host": "webcollect.org.uk", + "include_subdomains": true + }, + { + "host": "www.capitainetrain.com", + "include_subdomains": false + }, + { + "host": "accounts.firefox.com", + "include_subdomains": true + }, + { + "host": "z.ai", + "include_subdomains": true + }, + { + "host": "wildbee.org", + "include_subdomains": true + }, + { + "host": "portal.tirol.gv.at", + "include_subdomains": true + }, + { + "host": "dropbox.com", + "include_subdomains": false + }, + { + "host": "www.dropbox.com", + "include_subdomains": true + }, + { + "host": "code-poets.co.uk", + "include_subdomains": true + }, + { + "host": "jackyyf.com", + "include_subdomains": false + }, + { + "host": "flynn.io", + "include_subdomains": true + }, + { + "host": "hackerone.com", + "include_subdomains": true + }, + { + "host": "hackerone-user-content.com", + "include_subdomains": true + }, + { + "host": "gamesdepartment.co.uk", + "include_subdomains": false + }, + { + "host": "www.gamesdepartment.co.uk", + "include_subdomains": true + }, + { + "host": "schokokeks.org", + "include_subdomains": true + }, + { + "host": "mwe.st", + "include_subdomains": true + }, + { + "host": "ub3rk1tten.com", + "include_subdomains": true + }, + { + "host": "addvocate.com", + "include_subdomains": true + }, + { + "host": "alexsexton.com", + "include_subdomains": true + }, + { + "host": "azprep.us", + "include_subdomains": true + }, + { + "host": "beneathvt.com", + "include_subdomains": true + }, + { + "host": "cloudup.com", + "include_subdomains": true + }, + { + "host": "cryptopartyatx.org", + "include_subdomains": true + }, + { + "host": "cybershambles.com", + "include_subdomains": true + }, + { + "host": "ed.gs", + "include_subdomains": true + }, + { + "host": "forewordreviews.com", + "include_subdomains": true + }, + { + "host": "giacomopelagatti.it", + "include_subdomains": true + }, + { + "host": "helichat.de", + "include_subdomains": true + }, + { + "host": "hostinginnederland.nl", + "include_subdomains": true + }, + { + "host": "isitchristmas.com", + "include_subdomains": true + }, + { + "host": "konklone.com", + "include_subdomains": true + }, + { + "host": "koop-bremen.de", + "include_subdomains": true + }, + { + "host": "kura.io", + "include_subdomains": true + }, + { + "host": "markusueberallassetmanagement.de", + "include_subdomains": true + }, + { + "host": "mikewest.org", + "include_subdomains": true + }, + { + "host": "miskatonic.org", + "include_subdomains": true + }, + { + "host": "optimus.io", + "include_subdomains": true + }, + { + "host": "oversight.io", + "include_subdomains": true + }, + { + "host": "picksin.club", + "include_subdomains": true + }, + { + "host": "pressfreedomfoundation.org", + "include_subdomains": true + }, + { + "host": "projektzentrisch.de", + "include_subdomains": true + }, + { + "host": "rippleunion.com", + "include_subdomains": true + }, + { + "host": "robteix.com", + "include_subdomains": true + }, + { + "host": "s-c.se", + "include_subdomains": true + }, + { + "host": "security-carpet.com", + "include_subdomains": true + }, + { + "host": "sherbers.de", + "include_subdomains": true + }, + { + "host": "tittelbach.at", + "include_subdomains": true + }, + { + "host": "tomfisher.eu", + "include_subdomains": true + }, + { + "host": "wunderlist.com", + "include_subdomains": true + }, + { + "host": "zotero.org", + "include_subdomains": true + }, + { + "host": "adamkostecki.de", + "include_subdomains": true + }, + { + "host": "archlinux.de", + "include_subdomains": true + }, + { + "host": "auf-feindgebiet.de", + "include_subdomains": true + }, + { + "host": "baruch.me", + "include_subdomains": true + }, + { + "host": "bedeta.de", + "include_subdomains": true + }, + { + "host": "benjamins.com", + "include_subdomains": true + }, + { + "host": "bl4ckb0x.com", + "include_subdomains": true + }, + { + "host": "bl4ckb0x.de", + "include_subdomains": true + }, + { + "host": "bl4ckb0x.info", + "include_subdomains": true + }, + { + "host": "bl4ckb0x.net", + "include_subdomains": true + }, + { + "host": "bl4ckb0x.org", + "include_subdomains": true + }, + { + "host": "blocksatz-medien.de", + "include_subdomains": true + }, + { + "host": "conrad-kostecki.de", + "include_subdomains": true + }, + { + "host": "cube.de", + "include_subdomains": true + }, + { + "host": "datenkeks.de", + "include_subdomains": true + }, + { + "host": "derhil.de", + "include_subdomains": true + }, + { + "host": "energy-drink-magazin.de", + "include_subdomains": true + }, + { + "host": "ferienhaus-polchow-ruegen.de", + "include_subdomains": true + }, + { + "host": "fischer-its.com", + "include_subdomains": true + }, + { + "host": "freeshell.de", + "include_subdomains": true + }, + { + "host": "greensolid.biz", + "include_subdomains": true + }, + { + "host": "hasilocke.de", + "include_subdomains": true + }, + { + "host": "hausverbrauch.de", + "include_subdomains": true + }, + { + "host": "helpium.de", + "include_subdomains": true + }, + { + "host": "hex2013.com", + "include_subdomains": true + }, + { + "host": "honeytracks.com", + "include_subdomains": true + }, + { + "host": "ihrlotto.de", + "include_subdomains": true + }, + { + "host": "jonas-keidel.de", + "include_subdomains": true + }, + { + "host": "jonaswitmer.ch", + "include_subdomains": true + }, + { + "host": "k-dev.de", + "include_subdomains": true + }, + { + "host": "kraken.io", + "include_subdomains": true + }, + { + "host": "lagerauftrag.info", + "include_subdomains": true + }, + { + "host": "lavalite.de", + "include_subdomains": true + }, + { + "host": "loenshotel.de", + "include_subdomains": true + }, + { + "host": "loftboard.eu", + "include_subdomains": true + }, + { + "host": "mondwandler.de", + "include_subdomains": true + }, + { + "host": "mountainroseherbs.com", + "include_subdomains": true + }, + { + "host": "movlib.org", + "include_subdomains": true + }, + { + "host": "musicgamegalaxy.de", + "include_subdomains": true + }, + { + "host": "mynigma.org", + "include_subdomains": true + }, + { + "host": "nachsenden.info", + "include_subdomains": true + }, + { + "host": "netzbit.de", + "include_subdomains": true + }, + { + "host": "pdf.yt", + "include_subdomains": true + }, + { + "host": "pierre-schmitz.com", + "include_subdomains": true + }, + { + "host": "promecon-gmbh.de", + "include_subdomains": true + }, + { + "host": "prowhisky.de", + "include_subdomains": true + }, + { + "host": "pubkey.is", + "include_subdomains": true + }, + { + "host": "qetesh.de", + "include_subdomains": true + }, + { + "host": "riccy.org", + "include_subdomains": true + }, + { + "host": "scrambl.is", + "include_subdomains": true + }, + { + "host": "tageau.com", + "include_subdomains": true + }, + { + "host": "ukrainians.ch", + "include_subdomains": true + }, + { + "host": "viennan.net", + "include_subdomains": true + }, + { + "host": "winhistory-forum.net", + "include_subdomains": true + }, + { + "host": "y-o-w.com", + "include_subdomains": true + }, + { + "host": "explodie.org", + "include_subdomains": true + }, + { + "host": "aie.de", + "include_subdomains": true + }, + { + "host": "baer.im", + "include_subdomains": true + }, + { + "host": "bayrisch-fuer-anfaenger.de", + "include_subdomains": true + }, + { + "host": "beastowner.com", + "include_subdomains": true + }, + { + "host": "beastowner.li", + "include_subdomains": true + }, + { + "host": "best-wedding-quotes.com", + "include_subdomains": true + }, + { + "host": "bitfactory.ws", + "include_subdomains": true + }, + { + "host": "bohramt.de", + "include_subdomains": true + }, + { + "host": "buddhistische-weisheiten.org", + "include_subdomains": true + }, + { + "host": "cartouche24.eu", + "include_subdomains": true + }, + { + "host": "cartucce24.it", + "include_subdomains": true + }, + { + "host": "celltek-server.de", + "include_subdomains": true + }, + { + "host": "clapping-rhymes.com", + "include_subdomains": true + }, + { + "host": "die-besten-weisheiten.de", + "include_subdomains": true + }, + { + "host": "edyou.eu", + "include_subdomains": true + }, + { + "host": "eurotramp.com", + "include_subdomains": true + }, + { + "host": "forodeespanol.com", + "include_subdomains": true + }, + { + "host": "gemeinfreie-lieder.de", + "include_subdomains": true + }, + { + "host": "getdigitized.net", + "include_subdomains": true + }, + { + "host": "globuli-info.de", + "include_subdomains": true + }, + { + "host": "guphi.net", + "include_subdomains": true + }, + { + "host": "guthabenkarten-billiger.de", + "include_subdomains": true + }, + { + "host": "haufschild.de", + "include_subdomains": true + }, + { + "host": "hoerbuecher-und-hoerspiele.de", + "include_subdomains": true + }, + { + "host": "iban.is", + "include_subdomains": true + }, + { + "host": "irische-segenswuensche.info", + "include_subdomains": true + }, + { + "host": "it-schwerin.de", + "include_subdomains": true + }, + { + "host": "janus-engineering.de", + "include_subdomains": true + }, + { + "host": "jfreitag.de", + "include_subdomains": true + }, + { + "host": "julian-kipka.de", + "include_subdomains": true + }, + { + "host": "kardize24.pl", + "include_subdomains": true + }, + { + "host": "kernel-error.de", + "include_subdomains": true + }, + { + "host": "kinderbuecher-kostenlos.de", + "include_subdomains": true + }, + { + "host": "kitsta.com", + "include_subdomains": true + }, + { + "host": "klatschreime.de", + "include_subdomains": true + }, + { + "host": "kleidertauschpartys.de", + "include_subdomains": true + }, + { + "host": "koordinate.net", + "include_subdomains": true + }, + { + "host": "lasst-uns-beten.de", + "include_subdomains": true + }, + { + "host": "lb-toner.de", + "include_subdomains": true + }, + { + "host": "mandala-ausmalbilder.de", + "include_subdomains": true + }, + { + "host": "mathiasbynens.be", + "include_subdomains": true + }, + { + "host": "klaxn.com", + "include_subdomains": true + }, + { + "host": "mig5.net", + "include_subdomains": true + }, + { + "host": "netzpolitik.org", + "include_subdomains": true + }, + { + "host": "npw.net", + "include_subdomains": true + }, + { + "host": "otakuworld.de", + "include_subdomains": true + }, + { + "host": "pajonzeck.de", + "include_subdomains": true + }, + { + "host": "rad-route.de", + "include_subdomains": true + }, + { + "host": "raiseyourflag.com", + "include_subdomains": true + }, + { + "host": "redports.org", + "include_subdomains": true + }, + { + "host": "reserve-online.net", + "include_subdomains": true + }, + { + "host": "riesenmagnete.de", + "include_subdomains": true + }, + { + "host": "rosenkeller.org", + "include_subdomains": true + }, + { + "host": "salaervergleich.com", + "include_subdomains": true + }, + { + "host": "schwarzer.it", + "include_subdomains": true + }, + { + "host": "secuvera.de", + "include_subdomains": true + }, + { + "host": "siammedia.co", + "include_subdomains": true + }, + { + "host": "simplystudio.com", + "include_subdomains": true + }, + { + "host": "sprueche-zum-valentinstag.de", + "include_subdomains": true + }, + { + "host": "sprueche-zur-geburt.info", + "include_subdomains": true + }, + { + "host": "sprueche-zur-hochzeit.de", + "include_subdomains": true + }, + { + "host": "sprueche-zur-konfirmation.de", + "include_subdomains": true + }, + { + "host": "studydrive.net", + "include_subdomains": true + }, + { + "host": "supplies24.at", + "include_subdomains": true + }, + { + "host": "supplies24.es", + "include_subdomains": true + }, + { + "host": "tatort-fanpage.de", + "include_subdomains": true + }, + { + "host": "tektoria.de", + "include_subdomains": true + }, + { + "host": "texte-zur-taufe.de", + "include_subdomains": true + }, + { + "host": "tinte24.de", + "include_subdomains": true + }, + { + "host": "tintenfix.net", + "include_subdomains": true + }, + { + "host": "tipps-fuer-den-haushalt.de", + "include_subdomains": true + }, + { + "host": "toner24.at", + "include_subdomains": true + }, + { + "host": "toner24.co.uk", + "include_subdomains": true + }, + { + "host": "toner24.es", + "include_subdomains": true + }, + { + "host": "toner24.fr", + "include_subdomains": true + }, + { + "host": "toner24.it", + "include_subdomains": true + }, + { + "host": "toner24.nl", + "include_subdomains": true + }, + { + "host": "toner24.pl", + "include_subdomains": true + }, + { + "host": "tonerdepot.de", + "include_subdomains": true + }, + { + "host": "tonerjet.at", + "include_subdomains": true + }, + { + "host": "tonerjet.co.uk", + "include_subdomains": true + }, + { + "host": "tonerklick.de", + "include_subdomains": true + }, + { + "host": "tonerkurier.de", + "include_subdomains": true + }, + { + "host": "tonermaus.de", + "include_subdomains": true + }, + { + "host": "tonermonster.de", + "include_subdomains": true + }, + { + "host": "tonex.de", + "include_subdomains": true + }, + { + "host": "tonex.nl", + "include_subdomains": true + }, + { + "host": "trauertexte.info", + "include_subdomains": true + }, + { + "host": "unterfrankenclan.de", + "include_subdomains": true + }, + { + "host": "webandmore.de", + "include_subdomains": true + }, + { + "host": "welches-kinderfahrrad.de", + "include_subdomains": true + }, + { + "host": "apadvantage.com", + "include_subdomains": true + }, + { + "host": "apn-einstellungen.de", + "include_subdomains": true + }, + { + "host": "barcodeberlin.com", + "include_subdomains": true + }, + { + "host": "certible.com", + "include_subdomains": true + }, + { + "host": "data-abundance.com", + "include_subdomains": true + }, + { + "host": "dedimax.de", + "include_subdomains": true + }, + { + "host": "hostix.de", + "include_subdomains": true + }, + { + "host": "janoberst.com", + "include_subdomains": true + }, + { + "host": "jelmer.co.uk", + "include_subdomains": true + }, + { + "host": "jelmer.uk", + "include_subdomains": true + }, + { + "host": "munich-rage.de", + "include_subdomains": true + }, + { + "host": "posteo.de", + "include_subdomains": true + }, + { + "host": "stationary-traveller.eu", + "include_subdomains": true + }, + { + "host": "thepaymentscompany.com", + "include_subdomains": true + }, + { + "host": "xps2pdf.co.uk", + "include_subdomains": true + }, + { + "host": "ansdell.net", + "include_subdomains": true + }, + { + "host": "brunosouza.org", + "include_subdomains": true + }, + { + "host": "bugzil.la", + "include_subdomains": true + }, + { + "host": "bytepark.de", + "include_subdomains": true + }, + { + "host": "ethitter.com", + "include_subdomains": true + }, + { + "host": "firemail.io", + "include_subdomains": true + }, + { + "host": "gmantra.org", + "include_subdomains": true + }, + { + "host": "mach-politik.ch", + "include_subdomains": true + }, + { + "host": "malnex.de", + "include_subdomains": true + }, + { + "host": "mutantmonkey.sexy", + "include_subdomains": true + }, + { + "host": "ng-security.com", + "include_subdomains": true + }, + { + "host": "palava.tv", + "include_subdomains": true + }, + { + "host": "reedloden.com", + "include_subdomains": true + }, + { + "host": "rws-vertriebsportal.de", + "include_subdomains": true + }, + { + "host": "sdsl-speedtest.de", + "include_subdomains": true + }, + { + "host": "servethecity-karlsruhe.de", + "include_subdomains": true + }, + { + "host": "tunebitfm.de", + "include_subdomains": true + }, + { + "host": "websenat.de", + "include_subdomains": true + }, + { + "host": "zeropush.com", + "include_subdomains": true + }, + { + "host": "ludwig.im", + "include_subdomains": true + }, + { + "host": "gparent.org", + "include_subdomains": false + }, + { + "host": "blog.gparent.org", + "include_subdomains": false + }, + { + "host": "m.gparent.org", + "include_subdomains": false + }, + { + "host": "ca.gparent.org", + "include_subdomains": false + }, + { + "host": "simpletax.ca", + "include_subdomains": false + }, + { + "host": "help.simpletax.ca", + "include_subdomains": false + }, + { + "host": "app.simpletax.ca", + "include_subdomains": false + }, + { + "host": "daphne.informatik.uni-freiburg.de", + "include_subdomains": false + }, + { + "host": "bedreid.dk", + "include_subdomains": true + }, + { + "host": "cotonea.de", + "include_subdomains": true + }, + { + "host": "everhome.de", + "include_subdomains": true + }, + { + "host": "fixingdns.com", + "include_subdomains": true + }, + { + "host": "flamer-scene.com", + "include_subdomains": true + }, + { + "host": "insouciant.org", + "include_subdomains": true + }, + { + "host": "kaheim.de", + "include_subdomains": true + }, + { + "host": "kevincox.ca", + "include_subdomains": true + }, + { + "host": "lingolia.com", + "include_subdomains": true + }, + { + "host": "matatall.com", + "include_subdomains": true + }, + { + "host": "net-safe.info", + "include_subdomains": true + }, + { + "host": "okmx.de", + "include_subdomains": true + }, + { + "host": "osterkraenzchen.de", + "include_subdomains": true + }, + { + "host": "parent5446.us", + "include_subdomains": true + }, + { + "host": "patt.us", + "include_subdomains": true + }, + { + "host": "peercraft.com", + "include_subdomains": true + }, + { + "host": "room-checkin24.de", + "include_subdomains": true + }, + { + "host": "securify.nl", + "include_subdomains": true + }, + { + "host": "shaaaaaaaaaaaaa.com", + "include_subdomains": true + }, + { + "host": "shopontarget.com", + "include_subdomains": true + }, + { + "host": "siraweb.org", + "include_subdomains": true + }, + { + "host": "spdysync.com", + "include_subdomains": true + }, + { + "host": "sylaps.com", + "include_subdomains": true + }, + { + "host": "sysctl.se", + "include_subdomains": true + }, + { + "host": "tauchkater.de", + "include_subdomains": true + }, + { + "host": "theshadestore.com", + "include_subdomains": true + }, + { + "host": "tomvote.com", + "include_subdomains": true + }, + { + "host": "toshnix.com", + "include_subdomains": true + }, + { + "host": "warrencreative.com", + "include_subdomains": true + }, + { + "host": "zeplin.io", + "include_subdomains": true + }, + { + "host": "17hats.com", + "include_subdomains": true + }, + { + "host": "cdnb.co", + "include_subdomains": true + }, + { + "host": "github.com", + "include_subdomains": true + }, + { + "host": "id-co.in", + "include_subdomains": true + }, + { + "host": "ideaweb.de", + "include_subdomains": true + }, + { + "host": "man3s.jp", + "include_subdomains": true + }, + { + "host": "meinebo.it", + "include_subdomains": true + }, + { + "host": "nmctest.net", + "include_subdomains": true + }, + { + "host": "partyvan.eu", + "include_subdomains": true + }, + { + "host": "partyvan.it", + "include_subdomains": true + }, + { + "host": "partyvan.nl", + "include_subdomains": true + }, + { + "host": "partyvan.se", + "include_subdomains": true + }, + { + "host": "regar42.fr", + "include_subdomains": true + }, + { + "host": "scotthelme.co.uk", + "include_subdomains": true + }, + { + "host": "suite73.org", + "include_subdomains": true + }, + { + "host": "wubthecaptain.eu", + "include_subdomains": true + }, + { + "host": "1a-diamantscheiben.de", + "include_subdomains": true + }, + { + "host": "simplyfixit.co.uk", + "include_subdomains": true + }, + { + "host": "1a-vermessung.at", + "include_subdomains": true + }, + { + "host": "1a-werkstattgeraete.de", + "include_subdomains": true + }, + { + "host": "annahmeschluss.de", + "include_subdomains": true + }, + { + "host": "bautied.de", + "include_subdomains": true + }, + { + "host": "codepref.com", + "include_subdomains": true + }, + { + "host": "encryptallthethings.net", + "include_subdomains": true + }, + { + "host": "futos.de", + "include_subdomains": true + }, + { + "host": "jonnybarnes.uk", + "include_subdomains": true + }, + { + "host": "miasarafina.de", + "include_subdomains": true + }, + { + "host": "mothereff.in", + "include_subdomains": true + }, + { + "host": "mths.be", + "include_subdomains": true + }, + { + "host": "prefontaine.name", + "include_subdomains": true + }, + { + "host": "redlatam.org", + "include_subdomains": true + }, + { + "host": "schachburg.de", + "include_subdomains": true + }, + { + "host": "schreiber-netzwerk.eu", + "include_subdomains": true + }, + { + "host": "syss.de", + "include_subdomains": true + }, + { + "host": "terrax.berlin", + "include_subdomains": true + }, + { + "host": "tollmanz.com", + "include_subdomains": true + }, + { + "host": "tresorit.com", + "include_subdomains": true + }, + { + "host": "vaddder.com", + "include_subdomains": true + }, + { + "host": "wikidsystems.com", + "include_subdomains": true + }, + { + "host": "wohnungsbau-ludwigsburg.de", + "include_subdomains": true + }, + { + "host": "xtream-hosting.com", + "include_subdomains": true + }, + { + "host": "xtream-hosting.de", + "include_subdomains": true + }, + { + "host": "xtream-hosting.eu", + "include_subdomains": true + }, + { + "host": "xtreamhosting.eu", + "include_subdomains": true + }, + { + "host": "honeybadger.io", + "include_subdomains": false + }, + { + "host": "www.honeybadger.io", + "include_subdomains": false + }, + { + "host": "amigogeek.net", + "include_subdomains": true + }, + { + "host": "andreasbreitenlohner.de", + "include_subdomains": true + }, + { + "host": "aprz.de", + "include_subdomains": true + }, + { + "host": "arlen.io", + "include_subdomains": true + }, + { + "host": "bitfarm-archiv.com", + "include_subdomains": true + }, + { + "host": "bitfarm-archiv.de", + "include_subdomains": true + }, + { + "host": "bulktrade.de", + "include_subdomains": true + }, + { + "host": "buzzconcert.com", + "include_subdomains": true + }, + { + "host": "chulado.com", + "include_subdomains": true + }, + { + "host": "cimballa.com", + "include_subdomains": true + }, + { + "host": "daylightcompany.com", + "include_subdomains": true + }, + { + "host": "denh.am", + "include_subdomains": true + }, + { + "host": "devh.de", + "include_subdomains": true + }, + { + "host": "evstatus.com", + "include_subdomains": true + }, + { + "host": "filedir.com", + "include_subdomains": true + }, + { + "host": "frederik-braun.com", + "include_subdomains": true + }, + { + "host": "gplintegratedit.com", + "include_subdomains": true + }, + { + "host": "html5.org", + "include_subdomains": true + }, + { + "host": "ian.sh", + "include_subdomains": true + }, + { + "host": "ilikerainbows.co.uk", + "include_subdomains": true + }, + { + "host": "ilmconpm.de", + "include_subdomains": true + }, + { + "host": "inleaked.com", + "include_subdomains": true + }, + { + "host": "klaxn.org", + "include_subdomains": true + }, + { + "host": "labina.com.tr", + "include_subdomains": true + }, + { + "host": "liebel.org", + "include_subdomains": true + }, + { + "host": "luxus-russen.de", + "include_subdomains": true + }, + { + "host": "matteomarescotti.it", + "include_subdomains": true + }, + { + "host": "minikneet.com", + "include_subdomains": true + }, + { + "host": "minikneet.nl", + "include_subdomains": true + }, + { + "host": "mkcert.org", + "include_subdomains": true + }, + { + "host": "msc-seereisen.net", + "include_subdomains": true + }, + { + "host": "mykreuzfahrt.de", + "include_subdomains": true + }, + { + "host": "oscarvk.ch", + "include_subdomains": true + }, + { + "host": "plothost.com", + "include_subdomains": true + }, + { + "host": "reishunger.de", + "include_subdomains": true + }, + { + "host": "salserocafe.com", + "include_subdomains": true + }, + { + "host": "samizdat.cz", + "include_subdomains": true + }, + { + "host": "sslmate.com", + "include_subdomains": true + }, + { + "host": "steventress.com", + "include_subdomains": true + }, + { + "host": "tekshrek.com", + "include_subdomains": true + }, + { + "host": "temehu.com", + "include_subdomains": true + }, + { + "host": "tobias-kluge.de", + "include_subdomains": true + }, + { + "host": "vortexhobbies.com", + "include_subdomains": true + }, + { + "host": "willnorris.com", + "include_subdomains": true + }, + { + "host": "mykolab.com", + "include_subdomains": true + }, + { + "host": "semenkovich.com", + "include_subdomains": true + }, + { + "host": "rme.li", + "include_subdomains": false + }, + { + "host": "www.rme.li", + "include_subdomains": false + }, + { + "host": "aiticon.com", + "include_subdomains": true + }, + { + "host": "aiticon.de", + "include_subdomains": true + }, + { + "host": "anetaben.nl", + "include_subdomains": true + }, + { + "host": "annevankesteren.com", + "include_subdomains": true + }, + { + "host": "annevankesteren.nl", + "include_subdomains": true + }, + { + "host": "annevankesteren.org", + "include_subdomains": true + }, + { + "host": "barslecht.com", + "include_subdomains": true + }, + { + "host": "barslecht.nl", + "include_subdomains": true + }, + { + "host": "blessnet.jp", + "include_subdomains": true + }, + { + "host": "cloudstoragemaus.com", + "include_subdomains": true + }, + { + "host": "comdurav.com", + "include_subdomains": true + }, + { + "host": "digitaldaddy.net", + "include_subdomains": true + }, + { + "host": "elnutricionista.es", + "include_subdomains": true + }, + { + "host": "fronteers.nl", + "include_subdomains": true + }, + { + "host": "getssl.uz", + "include_subdomains": true + }, + { + "host": "gunnarhafdal.com", + "include_subdomains": true + }, + { + "host": "heijblok.com", + "include_subdomains": true + }, + { + "host": "kdex.de", + "include_subdomains": true + }, + { + "host": "limpid.nl", + "include_subdomains": true + }, + { + "host": "minez-nightswatch.com", + "include_subdomains": true + }, + { + "host": "pisidia.de", + "include_subdomains": true + }, + { + "host": "quuz.org", + "include_subdomains": true + }, + { + "host": "sale4ru.ru", + "include_subdomains": true + }, + { + "host": "shipard.com", + "include_subdomains": true + }, + { + "host": "sro.center", + "include_subdomains": true + }, + { + "host": "standardssuck.org", + "include_subdomains": true + }, + { + "host": "testsuite.org", + "include_subdomains": true + }, + { + "host": "thecustomizewindows.com", + "include_subdomains": true + }, + { + "host": "weggeweest.nl", + "include_subdomains": true + }, + { + "host": "whatwg.org", + "include_subdomains": true + }, + { + "host": "when-release.ru", + "include_subdomains": true + }, + { + "host": "xn--maraa-rta.org", + "include_subdomains": true + }, + { + "host": "otakurepublic.com", + "include_subdomains": true + }, + { + "host": "mqas.net", + "include_subdomains": true + }, + { + "host": "dlc.viasinc.com", + "include_subdomains": true + }, + { + "host": "www.viasinc.com", + "include_subdomains": true + }, + { + "host": "viasinc.com", + "include_subdomains": false + }, + { + "host": "angularjs.org", + "include_subdomains": true + }, + { + "host": "debtkit.co.uk", + "include_subdomains": true + }, + { + "host": "decibelios.li", + "include_subdomains": true + }, + { + "host": "diamante.ro", + "include_subdomains": true + }, + { + "host": "domaris.de", + "include_subdomains": true + }, + { + "host": "enorekcah.com", + "include_subdomains": true + }, + { + "host": "fedorapeople.org", + "include_subdomains": true + }, + { + "host": "gamercredo.com", + "include_subdomains": true + }, + { + "host": "garron.net", + "include_subdomains": true + }, + { + "host": "gerardozamudio.mx", + "include_subdomains": true + }, + { + "host": "gmcd.co", + "include_subdomains": true + }, + { + "host": "hack.li", + "include_subdomains": true + }, + { + "host": "hexony.com", + "include_subdomains": true + }, + { + "host": "horosho.in", + "include_subdomains": true + }, + { + "host": "howsmyssl.com", + "include_subdomains": true + }, + { + "host": "howsmytls.com", + "include_subdomains": true + }, + { + "host": "hpac-portal.com", + "include_subdomains": true + }, + { + "host": "jwilsson.me", + "include_subdomains": true + }, + { + "host": "khmath.com", + "include_subdomains": true + }, + { + "host": "knowledgehook.com", + "include_subdomains": true + }, + { + "host": "lodash.com", + "include_subdomains": true + }, + { + "host": "md5file.com", + "include_subdomains": true + }, + { + "host": "omitech.co.uk", + "include_subdomains": true + }, + { + "host": "orbograph-hrcm.com", + "include_subdomains": true + }, + { + "host": "password.codes", + "include_subdomains": true + }, + { + "host": "prakharprasad.com", + "include_subdomains": true + }, + { + "host": "ravchat.com", + "include_subdomains": true + }, + { + "host": "sciencex.com", + "include_subdomains": true + }, + { + "host": "shiinko.com", + "include_subdomains": true + }, + { + "host": "spideroak.com", + "include_subdomains": true + }, + { + "host": "thorncreek.net", + "include_subdomains": true + }, + { + "host": "tno.io", + "include_subdomains": true + }, + { + "host": "translatoruk.co.uk", + "include_subdomains": true + }, + { + "host": "wepay.in.th", + "include_subdomains": true + }, + { + "host": "zixiao.wang", + "include_subdomains": true + }, + { + "host": "at.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "au.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "az.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "be.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "bi.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "br.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ca.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "cd.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "cg.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "chfr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "chit.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ch.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "cl.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "cn.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "co.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "cr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ct.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "de.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "dk.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "do.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "en-maktoob.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "espanol.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "es.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "fi.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "fj.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "fr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "gl.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "gm.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "gr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "hk.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "hn.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "hu.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "id.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ie.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "in.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "it.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "kr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "kz.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "li.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "lt.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "lu.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "lv.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "maktoob.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "malaysia.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "mt.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "mu.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "mw.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "mx.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ni.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "nl.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "no.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "np.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "nz.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "pa.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "pe.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ph.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "pk.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "pl.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "pr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "py.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "qc.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ro.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ru.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "rw.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "se.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "sg.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "sv.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "th.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "tr.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "tv.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "tw.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ua.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "uk.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "search.yahoo.com", + "include_subdomains": false + }, + { + "host": "uy.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "uz.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "ve.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "vn.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "xa.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "za.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "zh.search.yahoo.com", + "include_subdomains": false + }, + { + "host": "login.yahoo.com", + "include_subdomains": true + }, + { + "host": "mail.yahoo.com", + "include_subdomains": false + }, + { + "host": "edit.yahoo.com", + "include_subdomains": true + }, + { + "host": "ahoyconference.com", + "include_subdomains": true + }, + { + "host": "balcan-underground.net", + "include_subdomains": true + }, + { + "host": "baldwinkoo.com", + "include_subdomains": true + }, + { + "host": "bigbrownpromotions.com.au", + "include_subdomains": true + }, + { + "host": "bodo-wolff.de", + "include_subdomains": true + }, + { + "host": "calibreapp.com", + "include_subdomains": true + }, + { + "host": "call.me", + "include_subdomains": true + }, + { + "host": "chrisjean.com", + "include_subdomains": true + }, + { + "host": "cujanovic.com", + "include_subdomains": true + }, + { + "host": "deadbeef.ninja", + "include_subdomains": true + }, + { + "host": "esec.rs", + "include_subdomains": true + }, + { + "host": "floobits.com", + "include_subdomains": true + }, + { + "host": "freenetproject.org", + "include_subdomains": true + }, + { + "host": "fundingempire.com", + "include_subdomains": true + }, + { + "host": "heid.ws", + "include_subdomains": true + }, + { + "host": "ironfistdesign.com", + "include_subdomains": true + }, + { + "host": "kinogb.net", + "include_subdomains": true + }, + { + "host": "ljs.io", + "include_subdomains": true + }, + { + "host": "lovelycorral.com", + "include_subdomains": true + }, + { + "host": "megashur.se", + "include_subdomains": true + }, + { + "host": "minnesotadata.com", + "include_subdomains": true + }, + { + "host": "mountainmusicpromotions.com", + "include_subdomains": true + }, + { + "host": "newstarnootropics.com", + "include_subdomains": true + }, + { + "host": "onedot.nl", + "include_subdomains": true + }, + { + "host": "powerplannerapp.com", + "include_subdomains": true + }, + { + "host": "ru-sprachstudio.ch", + "include_subdomains": true + }, + { + "host": "slattery.co", + "include_subdomains": true + }, + { + "host": "slidebatch.com", + "include_subdomains": true + }, + { + "host": "smartship.co.jp", + "include_subdomains": true + }, + { + "host": "southside-crew.com", + "include_subdomains": true + }, + { + "host": "tickopa.co.uk", + "include_subdomains": true + }, + { + "host": "wieninternational.at", + "include_subdomains": true + }, + { + "host": "fleximus.org", + "include_subdomains": true + }, + { + "host": "facebook.com", + "include_subdomains": false + }, + { + "host": "www.facebook.com", + "include_subdomains": true + }, + { + "host": "m.facebook.com", + "include_subdomains": true + }, + { + "host": "tablet.facebook.com", + "include_subdomains": true + }, + { + "host": "secure.facebook.com", + "include_subdomains": true + }, + { + "host": "pixel.facebook.com", + "include_subdomains": true + }, + { + "host": "apps.facebook.com", + "include_subdomains": true + }, + { + "host": "upload.facebook.com", + "include_subdomains": true + }, + { + "host": "developers.facebook.com", + "include_subdomains": true + }, + { + "host": "touch.facebook.com", + "include_subdomains": true + }, + { + "host": "mbasic.facebook.com", + "include_subdomains": true + }, + { + "host": "code.facebook.com", + "include_subdomains": true + }, + { + "host": "t.facebook.com", + "include_subdomains": true + }, + { + "host": "mtouch.facebook.com", + "include_subdomains": true + }, + { + "host": "business.facebook.com", + "include_subdomains": true + }, + { + "host": "research.facebook.com", + "include_subdomains": true + }, + { + "host": "0x0a.net", + "include_subdomains": true + }, + { + "host": "animurecs.com", + "include_subdomains": true + }, + { + "host": "arendburgers.nl", + "include_subdomains": true + }, + { + "host": "big-andy.co.uk", + "include_subdomains": true + }, + { + "host": "bitgo.com", + "include_subdomains": true + }, + { + "host": "buttercoin.com", + "include_subdomains": true + }, + { + "host": "chainmonitor.com", + "include_subdomains": true + }, + { + "host": "coinapult.com", + "include_subdomains": true + }, + { + "host": "comssa.org.au", + "include_subdomains": true + }, + { + "host": "coursella.com", + "include_subdomains": true + }, + { + "host": "crowdjuris.com", + "include_subdomains": true + }, + { + "host": "curlybracket.co.uk", + "include_subdomains": true + }, + { + "host": "cyanogenmod.xxx", + "include_subdomains": true + }, + { + "host": "czbix.com", + "include_subdomains": true + }, + { + "host": "dealcruiser.nl", + "include_subdomains": true + }, + { + "host": "derevtsov.com", + "include_subdomains": true + }, + { + "host": "dzlibs.io", + "include_subdomains": true + }, + { + "host": "easysimplecrm.com", + "include_subdomains": true + }, + { + "host": "fralef.me", + "include_subdomains": true + }, + { + "host": "glossopnorthendafc.co.uk", + "include_subdomains": true + }, + { + "host": "gtraxapp.com", + "include_subdomains": true + }, + { + "host": "hansvaneijsden.com", + "include_subdomains": true + }, + { + "host": "horseboners.xxx", + "include_subdomains": true + }, + { + "host": "horza.org", + "include_subdomains": true + }, + { + "host": "iamcarrico.com", + "include_subdomains": true + }, + { + "host": "kartonmodellbau.org", + "include_subdomains": true + }, + { + "host": "keycdn.com", + "include_subdomains": true + }, + { + "host": "komandakovalchuk.com", + "include_subdomains": true + }, + { + "host": "kryptera.se", + "include_subdomains": true + }, + { + "host": "lukonet.com", + "include_subdomains": true + }, + { + "host": "meetfinch.com", + "include_subdomains": true + }, + { + "host": "megaxchange.com", + "include_subdomains": true + }, + { + "host": "moriz.de", + "include_subdomains": true + }, + { + "host": "myplaceonline.com", + "include_subdomains": true + }, + { + "host": "nectarleaf.com", + "include_subdomains": true + }, + { + "host": "nos-oignons.net", + "include_subdomains": true + }, + { + "host": "phoenixlogan.com", + "include_subdomains": true + }, + { + "host": "redteam-pentesting.de", + "include_subdomains": true + }, + { + "host": "roland.io", + "include_subdomains": true + }, + { + "host": "servergno.me", + "include_subdomains": true + }, + { + "host": "siriad.com", + "include_subdomains": true + }, + { + "host": "smartcoin.com.br", + "include_subdomains": true + }, + { + "host": "spartantheatre.org", + "include_subdomains": true + }, + { + "host": "spencerbaer.com", + "include_subdomains": true + }, + { + "host": "stretchmyan.us", + "include_subdomains": true + }, + { + "host": "taxsquirrel.com", + "include_subdomains": true + }, + { + "host": "techhipster.net", + "include_subdomains": true + }, + { + "host": "timtaubert.de", + "include_subdomains": true + }, + { + "host": "tribut.de", + "include_subdomains": true + }, + { + "host": "triop.se", + "include_subdomains": true + }, + { + "host": "twentymilliseconds.com", + "include_subdomains": true + }, + { + "host": "ukdefencejournal.org.uk", + "include_subdomains": true + }, + { + "host": "ukhas.net", + "include_subdomains": true + }, + { + "host": "vpnzoom.com", + "include_subdomains": true + }, + { + "host": "watsonhall.uk", + "include_subdomains": true + }, + { + "host": "weblogzwolle.nl", + "include_subdomains": true + }, + { + "host": "ypart.eu", + "include_subdomains": true + }, + { + "host": "www.etsy.com", + "include_subdomains": true + }, + { + "host": "etsysecure.com", + "include_subdomains": true + }, + { + "host": "18f.gsa.gov", + "include_subdomains": true + }, + { + "host": "my.usa.gov", + "include_subdomains": true + }, + { + "host": "alexyang.me", + "include_subdomains": true + }, + { + "host": "beamitapp.com", + "include_subdomains": true + }, + { + "host": "bonigo.de", + "include_subdomains": true + }, + { + "host": "certly.io", + "include_subdomains": true + }, + { + "host": "chontalpa.pw", + "include_subdomains": true + }, + { + "host": "cktennis.com", + "include_subdomains": true + }, + { + "host": "clintwilson.technology", + "include_subdomains": true + }, + { + "host": "cspbuilder.info", + "include_subdomains": true + }, + { + "host": "depechemode-live.com", + "include_subdomains": true + }, + { + "host": "destinationbijoux.fr", + "include_subdomains": true + }, + { + "host": "dinamoelektrik.com", + "include_subdomains": true + }, + { + "host": "ethack.org", + "include_subdomains": true + }, + { + "host": "fabianfischer.de", + "include_subdomains": true + }, + { + "host": "fastcomcorp.net", + "include_subdomains": true + }, + { + "host": "gizzo.sk", + "include_subdomains": true + }, + { + "host": "inkbunny.net", + "include_subdomains": true + }, + { + "host": "itsamurai.ru", + "include_subdomains": true + }, + { + "host": "itshost.ru", + "include_subdomains": true + }, + { + "host": "jmedved.com", + "include_subdomains": true + }, + { + "host": "jwilsson.com", + "include_subdomains": true + }, + { + "host": "keepclean.me", + "include_subdomains": true + }, + { + "host": "klausbrinch.dk", + "include_subdomains": true + }, + { + "host": "leonardcamacho.me", + "include_subdomains": true + }, + { + "host": "mdfnet.se", + "include_subdomains": true + }, + { + "host": "michalspacek.cz", + "include_subdomains": true + }, + { + "host": "mike-bland.com", + "include_subdomains": true + }, + { + "host": "mocloud.eu", + "include_subdomains": true + }, + { + "host": "oakslighting.co.uk", + "include_subdomains": true + }, + { + "host": "onsitemassageco.com", + "include_subdomains": true + }, + { + "host": "propagandism.org", + "include_subdomains": true + }, + { + "host": "slevomat.cz", + "include_subdomains": true + }, + { + "host": "sour.is", + "include_subdomains": true + }, + { + "host": "spongepowered.org", + "include_subdomains": true + }, + { + "host": "staticanime.net", + "include_subdomains": true + }, + { + "host": "sunjaydhama.com", + "include_subdomains": true + }, + { + "host": "swehack.org", + "include_subdomains": true + }, + { + "host": "thusoy.com", + "include_subdomains": true + }, + { + "host": "tls.li", + "include_subdomains": true + }, + { + "host": "vhost.co.id", + "include_subdomains": true + }, + { + "host": "webandwords.com.au", + "include_subdomains": true + }, + { + "host": "webtiles.co.uk", + "include_subdomains": true + }, + { + "host": "yoursecondphone.co", + "include_subdomains": true + }, + { + "host": "zlavomat.sk", + "include_subdomains": true + }, + { + "host": "alainwolf.net", + "include_subdomains": true + }, + { + "host": "arguggi.co.uk", + "include_subdomains": true + }, + { + "host": "azabani.com", + "include_subdomains": true + }, + { + "host": "bitmon.net", + "include_subdomains": true + }, + { + "host": "bjornjohansen.no", + "include_subdomains": true + }, + { + "host": "bookingapp.nl", + "include_subdomains": true + }, + { + "host": "cackette.com", + "include_subdomains": true + }, + { + "host": "caremad.io", + "include_subdomains": true + }, + { + "host": "clerkendweller.uk", + "include_subdomains": true + }, + { + "host": "cyon.ch", + "include_subdomains": true + }, + { + "host": "fakturoid.cz", + "include_subdomains": true + }, + { + "host": "finn.io", + "include_subdomains": true + }, + { + "host": "fm83.nl", + "include_subdomains": true + }, + { + "host": "grandmascookieblog.com", + "include_subdomains": true + }, + { + "host": "khanovaskola.cz", + "include_subdomains": true + }, + { + "host": "ki-on.net", + "include_subdomains": true + }, + { + "host": "kingmanhall.org", + "include_subdomains": true + }, + { + "host": "kpebetka.net", + "include_subdomains": true + }, + { + "host": "mirindadomo.ru", + "include_subdomains": true + }, + { + "host": "myvirtualserver.com", + "include_subdomains": true + }, + { + "host": "neftaly.com", + "include_subdomains": true + }, + { + "host": "nu3.at", + "include_subdomains": true + }, + { + "host": "nu3.ch", + "include_subdomains": true + }, + { + "host": "nu3.co.uk", + "include_subdomains": true + }, + { + "host": "nu3.com", + "include_subdomains": true + }, + { + "host": "nu3.de", + "include_subdomains": true + }, + { + "host": "nu3.dk", + "include_subdomains": true + }, + { + "host": "nu3.fi", + "include_subdomains": true + }, + { + "host": "nu3.fr", + "include_subdomains": true + }, + { + "host": "nu3.no", + "include_subdomains": true + }, + { + "host": "nu3.se", + "include_subdomains": true + }, + { + "host": "ovenapp.io", + "include_subdomains": true + }, + { + "host": "ruudkoot.nl", + "include_subdomains": true + }, + { + "host": "seomobo.com", + "include_subdomains": true + }, + { + "host": "seowarp.net", + "include_subdomains": true + }, + { + "host": "shenyuqi.com", + "include_subdomains": true + }, + { + "host": "souvik.me", + "include_subdomains": true + }, + { + "host": "topodin.com", + "include_subdomains": true + }, + { + "host": "wpletter.de", + "include_subdomains": true + }, + { + "host": "yahvehyireh.com", + "include_subdomains": true + }, + { + "host": "anadoluefessporkulubu.org", + "include_subdomains": true + }, + { + "host": "ankarakart.com.tr", + "include_subdomains": true + }, + { + "host": "bgneuesheim.de", + "include_subdomains": true + }, + { + "host": "bhatia.at", + "include_subdomains": true + }, + { + "host": "bitmex.com", + "include_subdomains": true + }, + { + "host": "blockchain.info", + "include_subdomains": true + }, + { + "host": "blubbablasen.de", + "include_subdomains": true + }, + { + "host": "brage.info", + "include_subdomains": true + }, + { + "host": "chahub.com", + "include_subdomains": true + }, + { + "host": "cor-ser.es", + "include_subdomains": true + }, + { + "host": "darchoods.net", + "include_subdomains": true + }, + { + "host": "electronic-ignition-system.com", + "include_subdomains": true + }, + { + "host": "fabhub.io", + "include_subdomains": true + }, + { + "host": "fant.dk", + "include_subdomains": true + }, + { + "host": "henriknoerr.com", + "include_subdomains": true + }, + { + "host": "imaginary.ca", + "include_subdomains": true + }, + { + "host": "inb4.us", + "include_subdomains": true + }, + { + "host": "kosho.org", + "include_subdomains": true + }, + { + "host": "lighting-centres.co.uk", + "include_subdomains": true + }, + { + "host": "marshut.net", + "include_subdomains": true + }, + { + "host": "meamod.com", + "include_subdomains": true + }, + { + "host": "myni.io", + "include_subdomains": true + }, + { + "host": "nameid.org", + "include_subdomains": true + }, + { + "host": "nginxnudes.com", + "include_subdomains": true + }, + { + "host": "nouvelle-vague-saint-cast.fr", + "include_subdomains": true + }, + { + "host": "opendesk.cc", + "include_subdomains": true + }, + { + "host": "pestici.de", + "include_subdomains": true + }, + { + "host": "petrolplus.ru", + "include_subdomains": true + }, + { + "host": "proximato.com", + "include_subdomains": true + }, + { + "host": "savetheinternet.eu", + "include_subdomains": true + }, + { + "host": "shortdiary.me", + "include_subdomains": true + }, + { + "host": "simplia.cz", + "include_subdomains": true + }, + { + "host": "tadigitalstore.com", + "include_subdomains": true + }, + { + "host": "tapka.cz", + "include_subdomains": true + }, + { + "host": "tegelsensanitaironline.nl", + "include_subdomains": true + }, + { + "host": "typingrevolution.com", + "include_subdomains": true + }, + { + "host": "unison.com", + "include_subdomains": true + }, + { + "host": "uptrends.com", + "include_subdomains": true + }, + { + "host": "visionless.me", + "include_subdomains": true + }, + { + "host": "vrobert.fr", + "include_subdomains": true + }, + { + "host": "wbg-vs.de", + "include_subdomains": true + }, + { + "host": "hstspreload.appspot.com", + "include_subdomains": true + }, + { + "host": "hg.python.org", + "include_subdomains": true + }, + { + "host": "doc.python.org", + "include_subdomains": true + }, + { + "host": "console.python.org", + "include_subdomains": true + }, + { + "host": "mutantmonkey.in", + "include_subdomains": true + }, + { + "host": "mutantmonkey.info", + "include_subdomains": true + }, + { + "host": "alecvannoten.be", + "include_subdomains": true + }, + { + "host": "anime.my", + "include_subdomains": true + }, + { + "host": "atavio.at", + "include_subdomains": true + }, + { + "host": "atavio.ch", + "include_subdomains": true + }, + { + "host": "atavio.de", + "include_subdomains": true + }, + { + "host": "balikonos.cz", + "include_subdomains": true + }, + { + "host": "camolist.com", + "include_subdomains": true + }, + { + "host": "chatbot.me", + "include_subdomains": true + }, + { + "host": "coffeeetc.co.uk", + "include_subdomains": true + }, + { + "host": "dee.pe", + "include_subdomains": true + }, + { + "host": "ecdn.cz", + "include_subdomains": true + }, + { + "host": "ef.gy", + "include_subdomains": true + }, + { + "host": "exiahost.com", + "include_subdomains": true + }, + { + "host": "freethought.org.au", + "include_subdomains": true + }, + { + "host": "hrackydomino.cz", + "include_subdomains": true + }, + { + "host": "hsmr.cc", + "include_subdomains": true + }, + { + "host": "instasex.ch", + "include_subdomains": true + }, + { + "host": "jakub-boucek.cz", + "include_subdomains": true + }, + { + "host": "koenvdheuvel.me", + "include_subdomains": true + }, + { + "host": "leadbook.ru", + "include_subdomains": true + }, + { + "host": "lilpwny.com", + "include_subdomains": true + }, + { + "host": "mirrorx.com", + "include_subdomains": true + }, + { + "host": "pentesterlab.com", + "include_subdomains": true + }, + { + "host": "pypa.io", + "include_subdomains": true + }, + { + "host": "r3s1stanc3.me", + "include_subdomains": true + }, + { + "host": "residentsinsurance.co.uk", + "include_subdomains": true + }, + { + "host": "rlalique.com", + "include_subdomains": true + }, + { + "host": "scribe.systems", + "include_subdomains": true + }, + { + "host": "securesuisse.ch", + "include_subdomains": true + }, + { + "host": "slack.com", + "include_subdomains": true + }, + { + "host": "smartlend.se", + "include_subdomains": true + }, + { + "host": "webtrh.cz", + "include_subdomains": true + }, + { + "host": "yetii.net", + "include_subdomains": true + }, + { + "host": "login.ubuntu.com", + "include_subdomains": true + }, + { + "host": "login.launchpad.net", + "include_subdomains": true + }, + { + "host": "302.nyc", + "include_subdomains": true + }, + { + "host": "biathloncup.ru", + "include_subdomains": true + }, + { + "host": "bitpod.de", + "include_subdomains": true + }, + { + "host": "brakemanpro.com", + "include_subdomains": true + }, + { + "host": "daveoc64.co.uk", + "include_subdomains": true + }, + { + "host": "fewo-thueringer-wald.de", + "include_subdomains": true + }, + { + "host": "filip-prochazka.com", + "include_subdomains": true + }, + { + "host": "food4health.guide", + "include_subdomains": true + }, + { + "host": "johners.me", + "include_subdomains": true + }, + { + "host": "kdyby.org", + "include_subdomains": true + }, + { + "host": "kupschke.net", + "include_subdomains": true + }, + { + "host": "leibniz-remscheid.de", + "include_subdomains": true + }, + { + "host": "manicode.com", + "include_subdomains": true + }, + { + "host": "nwgh.org", + "include_subdomains": true + }, + { + "host": "ouvirmusica.com.br", + "include_subdomains": true + }, + { + "host": "pharmaboard.de", + "include_subdomains": true + }, + { + "host": "pieperhome.de", + "include_subdomains": true + }, + { + "host": "raspass.me", + "include_subdomains": true + }, + { + "host": "romans-place.me.uk", + "include_subdomains": true + }, + { + "host": "rudloff.pro", + "include_subdomains": true + }, + { + "host": "seyahatsagliksigortalari.com", + "include_subdomains": true + }, + { + "host": "shakepeers.org", + "include_subdomains": true + }, + { + "host": "smartcleaningcenter.nl", + "include_subdomains": true + }, + { + "host": "snakehosting.dk", + "include_subdomains": true + }, + { + "host": "srevilak.net", + "include_subdomains": true + }, + { + "host": "strasweb.fr", + "include_subdomains": true + }, + { + "host": "tas2580.net", + "include_subdomains": true + }, + { + "host": "todesschaf.org", + "include_subdomains": true + }, + { + "host": "twisto.cz", + "include_subdomains": true + }, + { + "host": "webassadors.com", + "include_subdomains": true + }, + { + "host": "wundi.net", + "include_subdomains": true + }, + { + "host": "007sascha.de", + "include_subdomains": true + }, + { + "host": "2048game.co.uk", + "include_subdomains": true + }, + { + "host": "adorai.tk", + "include_subdomains": true + }, + { + "host": "afp548.com", + "include_subdomains": true + }, + { + "host": "atlassian.net", + "include_subdomains": true + }, + { + "host": "atte.fi", + "include_subdomains": true + }, + { + "host": "bizon.sk", + "include_subdomains": true + }, + { + "host": "broeselei.at", + "include_subdomains": true + }, + { + "host": "cordial-restaurant.com", + "include_subdomains": true + }, + { + "host": "curiosity-driven.org", + "include_subdomains": true + }, + { + "host": "egfl.org.uk", + "include_subdomains": true + }, + { + "host": "eksisozluk.com", + "include_subdomains": true + }, + { + "host": "firefart.at", + "include_subdomains": true + }, + { + "host": "firstlook.org", + "include_subdomains": true + }, + { + "host": "fonetiq.io", + "include_subdomains": true + }, + { + "host": "groetzner.net", + "include_subdomains": true + }, + { + "host": "gw2treasures.com", + "include_subdomains": true + }, + { + "host": "heartlandrentals.com", + "include_subdomains": true + }, + { + "host": "hemlockhillscabinrentals.com", + "include_subdomains": true + }, + { + "host": "hstsfail.appspot.com", + "include_subdomains": true + }, + { + "host": "i5y.co.uk", + "include_subdomains": true + }, + { + "host": "innophate-security.com", + "include_subdomains": true + }, + { + "host": "innophate-security.nl", + "include_subdomains": true + }, + { + "host": "iranianlawschool.com", + "include_subdomains": true + }, + { + "host": "jettshome.org", + "include_subdomains": true + }, + { + "host": "karmaspa.se", + "include_subdomains": true + }, + { + "host": "keeleysam.com", + "include_subdomains": true + }, + { + "host": "kirkforcongress.com", + "include_subdomains": true + }, + { + "host": "kirkforsenate.com", + "include_subdomains": true + }, + { + "host": "les-corsaires.net", + "include_subdomains": true + }, + { + "host": "libraryfreedomproject.org", + "include_subdomains": true + }, + { + "host": "linux-admin-california.com", + "include_subdomains": true + }, + { + "host": "lobste.rs", + "include_subdomains": true + }, + { + "host": "luelistan.net", + "include_subdomains": true + }, + { + "host": "makeitdynamic.com", + "include_subdomains": true + }, + { + "host": "minecraftvoter.com", + "include_subdomains": true + }, + { + "host": "mkw.st", + "include_subdomains": true + }, + { + "host": "mujadin.se", + "include_subdomains": true + }, + { + "host": "netztest.at", + "include_subdomains": true + }, + { + "host": "null-sec.ru", + "include_subdomains": true + }, + { + "host": "nutsandboltsmedia.com", + "include_subdomains": true + }, + { + "host": "ooonja.de", + "include_subdomains": true + }, + { + "host": "personaldatabasen.no", + "include_subdomains": true + }, + { + "host": "phurl.de", + "include_subdomains": true + }, + { + "host": "privategiant.com", + "include_subdomains": true + }, + { + "host": "progressiveplanning.com", + "include_subdomains": true + }, + { + "host": "puac.de", + "include_subdomains": true + }, + { + "host": "rafaelcz.de", + "include_subdomains": true + }, + { + "host": "rasing.me", + "include_subdomains": true + }, + { + "host": "reliable-mail.de", + "include_subdomains": true + }, + { + "host": "romulusapp.com", + "include_subdomains": true + }, + { + "host": "samba.org", + "include_subdomains": true + }, + { + "host": "savvytime.com", + "include_subdomains": true + }, + { + "host": "sitesten.com", + "include_subdomains": true + }, + { + "host": "skhosting.eu", + "include_subdomains": true + }, + { + "host": "skogsbruket.fi", + "include_subdomains": true + }, + { + "host": "skogskultur.fi", + "include_subdomains": true + }, + { + "host": "sorz.org", + "include_subdomains": true + }, + { + "host": "spawn.cz", + "include_subdomains": true + }, + { + "host": "spreed.me", + "include_subdomains": true + }, + { + "host": "studienportal.eu", + "include_subdomains": true + }, + { + "host": "tc-bonito.de", + "include_subdomains": true + }, + { + "host": "thomasgriffin.io", + "include_subdomains": true + }, + { + "host": "thyngster.com", + "include_subdomains": true + }, + { + "host": "tid.jp", + "include_subdomains": true + }, + { + "host": "tonywebster.com", + "include_subdomains": true + }, + { + "host": "tucuxi.org", + "include_subdomains": true + }, + { + "host": "firebaseio.com", + "include_subdomains": true + }, + { + "host": "firebaseio-demo.com", + "include_subdomains": true + }, + { + "host": "adlershop.ch", + "include_subdomains": true + }, + { + "host": "ahwatukeefoothillsmontessori.com", + "include_subdomains": true + }, + { + "host": "authentication.io", + "include_subdomains": true + }, + { + "host": "brainfork.ml", + "include_subdomains": true + }, + { + "host": "brainvation.de", + "include_subdomains": true + }, + { + "host": "brossmanit.com", + "include_subdomains": true + }, + { + "host": "calomel.org", + "include_subdomains": true + }, + { + "host": "chm.vn", + "include_subdomains": true + }, + { + "host": "clan-ww.com", + "include_subdomains": true + }, + { + "host": "dixmag.com", + "include_subdomains": true + }, + { + "host": "dynaloop.net", + "include_subdomains": true + }, + { + "host": "eduroam.no", + "include_subdomains": true + }, + { + "host": "egit.co", + "include_subdomains": true + }, + { + "host": "gambitnash.co.uk", + "include_subdomains": true + }, + { + "host": "gavick.com", + "include_subdomains": true + }, + { + "host": "hachre.de", + "include_subdomains": true + }, + { + "host": "herocentral.de", + "include_subdomains": true + }, + { + "host": "hicoria.com", + "include_subdomains": true + }, + { + "host": "id-conf.com", + "include_subdomains": true + }, + { + "host": "ikkatsu-satei.jp", + "include_subdomains": true + }, + { + "host": "iridiumbrowser.de", + "include_subdomains": true + }, + { + "host": "jira.com", + "include_subdomains": true + }, + { + "host": "kirei.se", + "include_subdomains": true + }, + { + "host": "kuppingercole.com", + "include_subdomains": true + }, + { + "host": "maff.scot", + "include_subdomains": true + }, + { + "host": "mpreserver.com", + "include_subdomains": true + }, + { + "host": "mvno.io", + "include_subdomains": true + }, + { + "host": "namepros.com", + "include_subdomains": true + }, + { + "host": "neko.li", + "include_subdomains": true + }, + { + "host": "netera.se", + "include_subdomains": true + }, + { + "host": "nieselregen.com", + "include_subdomains": true + }, + { + "host": "pauladamsmith.com", + "include_subdomains": true + }, + { + "host": "pwd.ovh", + "include_subdomains": true + }, + { + "host": "ragingserenity.com", + "include_subdomains": true + }, + { + "host": "saintsrobotics.com", + "include_subdomains": true + }, + { + "host": "samuelkeeley.com", + "include_subdomains": true + }, + { + "host": "shellsec.pw", + "include_subdomains": true + }, + { + "host": "suzukikenichi.com", + "include_subdomains": true + }, + { + "host": "tbspace.de", + "include_subdomains": true + }, + { + "host": "the-sky-of-valkyries.com", + "include_subdomains": true + }, + { + "host": "thomastimepieces.com.au", + "include_subdomains": true + }, + { + "host": "uonstaffhub.com", + "include_subdomains": true + }, + { + "host": "whd-guide.de", + "include_subdomains": true + }, + { + "host": "whocalld.com", + "include_subdomains": true + }, + { + "host": "wootton95.com", + "include_subdomains": true + }, + { + "host": "fassadenverkleidung24.de", + "include_subdomains": true + }, + { + "host": "uspsoig.gov", + "include_subdomains": true + }, + { + "host": "notalone.gov", + "include_subdomains": true + }, + { + "host": "aids.gov", + "include_subdomains": true + }, + { + "host": "itdashboard.gov", + "include_subdomains": true + }, + { + "host": "paymentaccuracy.gov", + "include_subdomains": true + }, + { + "host": "cao.gov", + "include_subdomains": true + }, + { + "host": "cfo.gov", + "include_subdomains": true + }, + { + "host": "cio.gov", + "include_subdomains": true + }, + { + "host": "earmarks.gov", + "include_subdomains": true + }, + { + "host": "bfelob.gov", + "include_subdomains": true + }, + { + "host": "max.gov", + "include_subdomains": true + }, + { + "host": "save.gov", + "include_subdomains": true + }, + { + "host": "saveaward.gov", + "include_subdomains": true + }, + { + "host": "ustr.gov", + "include_subdomains": true + }, + { + "host": "airlea.com", + "include_subdomains": true + }, + { + "host": "atlantischild.hu", + "include_subdomains": true + }, + { + "host": "benjamin.pe", + "include_subdomains": true + }, + { + "host": "changelab.cc", + "include_subdomains": true + }, + { + "host": "cryptobin.org", + "include_subdomains": true + }, + { + "host": "csuw.net", + "include_subdomains": true + }, + { + "host": "dccode.gov", + "include_subdomains": true + }, + { + "host": "dreadbyte.com", + "include_subdomains": true + }, + { + "host": "dylanscott.com.au", + "include_subdomains": true + }, + { + "host": "e-kontakti.fi", + "include_subdomains": true + }, + { + "host": "ecfs.link", + "include_subdomains": true + }, + { + "host": "expatads.com", + "include_subdomains": true + }, + { + "host": "florianmitrea.uk", + "include_subdomains": true + }, + { + "host": "gaytorrent.ru", + "include_subdomains": true + }, + { + "host": "getable.com", + "include_subdomains": true + }, + { + "host": "gpsfix.cz", + "include_subdomains": true + }, + { + "host": "guidetoiceland.is", + "include_subdomains": true + }, + { + "host": "happylifestyle.com", + "include_subdomains": true + }, + { + "host": "heppler.net", + "include_subdomains": true + }, + { + "host": "httpswatch.com", + "include_subdomains": true + }, + { + "host": "interserved.com", + "include_subdomains": true + }, + { + "host": "izdiwho.com", + "include_subdomains": true + }, + { + "host": "jimshaver.net", + "include_subdomains": true + }, + { + "host": "jmdekker.it", + "include_subdomains": true + }, + { + "host": "jonathan.ir", + "include_subdomains": true + }, + { + "host": "klarmobil-empfehlen.de", + "include_subdomains": true + }, + { + "host": "klingeletest.de", + "include_subdomains": true + }, + { + "host": "lancejames.com", + "include_subdomains": true + }, + { + "host": "leonklingele.de", + "include_subdomains": true + }, + { + "host": "madars.org", + "include_subdomains": true + }, + { + "host": "magneticanvil.com", + "include_subdomains": true + }, + { + "host": "mimeit.de", + "include_subdomains": true + }, + { + "host": "mobilcom-debitel-empfehlen.de", + "include_subdomains": true + }, + { + "host": "morethanadream.lv", + "include_subdomains": true + }, + { + "host": "narodniki.com", + "include_subdomains": true + }, + { + "host": "netrider.net.au", + "include_subdomains": true + }, + { + "host": "niloxy.com", + "include_subdomains": true + }, + { + "host": "noobs-r-us.co.uk", + "include_subdomains": true + }, + { + "host": "nowhere.dk", + "include_subdomains": true + }, + { + "host": "perfectionis.me", + "include_subdomains": true + }, + { + "host": "phryanjr.com", + "include_subdomains": true + }, + { + "host": "polymathematician.com", + "include_subdomains": true + }, + { + "host": "sanatfilan.com", + "include_subdomains": true + }, + { + "host": "sikayetvar.com", + "include_subdomains": true + }, + { + "host": "stulda.cz", + "include_subdomains": true + }, + { + "host": "sysdb.io", + "include_subdomains": true + }, + { + "host": "tallshoe.com", + "include_subdomains": true + }, + { + "host": "thetomharling.com", + "include_subdomains": true + }, + { + "host": "tracktivity.com.au", + "include_subdomains": true + }, + { + "host": "twitteroauth.com", + "include_subdomains": true + }, + { + "host": "vitrado.de", + "include_subdomains": true + }, + { + "host": "webtalis.nl", + "include_subdomains": true + }, + { + "host": "wevahoo.com", + "include_subdomains": true + }, + { + "host": "zentralwolke.de", + "include_subdomains": true + }, + { + "host": "zhovner.com", + "include_subdomains": true + }, + { + "host": "acus.gov", + "include_subdomains": true + }, + { + "host": "agrimap.com", + "include_subdomains": true + }, + { + "host": "ajouin.com", + "include_subdomains": true + }, + { + "host": "atishchenko.com", + "include_subdomains": true + }, + { + "host": "bentertain.de", + "include_subdomains": true + }, + { + "host": "bit.voyage", + "include_subdomains": true + }, + { + "host": "bzv-fr.eu", + "include_subdomains": true + }, + { + "host": "codepoints.net", + "include_subdomains": true + }, + { + "host": "codepx.com", + "include_subdomains": true + }, + { + "host": "cyprus-company-service.com", + "include_subdomains": true + }, + { + "host": "darkpony.ru", + "include_subdomains": true + }, + { + "host": "darom.jp", + "include_subdomains": true + }, + { + "host": "davidnoren.com", + "include_subdomains": true + }, + { + "host": "donotcall.gov", + "include_subdomains": true + }, + { + "host": "e-aut.net", + "include_subdomains": true + }, + { + "host": "ecg.fr", + "include_subdomains": true + }, + { + "host": "exon.io", + "include_subdomains": true + }, + { + "host": "extendwings.com", + "include_subdomains": true + }, + { + "host": "federalregister.gov", + "include_subdomains": true + }, + { + "host": "fedorahosted.org", + "include_subdomains": true + }, + { + "host": "firma-offshore.com", + "include_subdomains": true + }, + { + "host": "freesounding.com", + "include_subdomains": true + }, + { + "host": "freesounding.ru", + "include_subdomains": true + }, + { + "host": "ftccomplaintassistant.gov", + "include_subdomains": true + }, + { + "host": "getfedora.org", + "include_subdomains": true + }, + { + "host": "getfittedstore.com", + "include_subdomains": true + }, + { + "host": "hatoko.net", + "include_subdomains": true + }, + { + "host": "hda.me", + "include_subdomains": true + }, + { + "host": "helpadmin.net", + "include_subdomains": true + }, + { + "host": "hsr.gov", + "include_subdomains": true + }, + { + "host": "iniiter.com", + "include_subdomains": true + }, + { + "host": "ionas-law.ro", + "include_subdomains": true + }, + { + "host": "keepa.com", + "include_subdomains": true + }, + { + "host": "knip.ch", + "include_subdomains": true + }, + { + "host": "laf.in.net", + "include_subdomains": true + }, + { + "host": "leifdreizler.com", + "include_subdomains": true + }, + { + "host": "livej.am", + "include_subdomains": true + }, + { + "host": "m0wef.uk", + "include_subdomains": true + }, + { + "host": "mahamed91.pw", + "include_subdomains": true + }, + { + "host": "massivum.de", + "include_subdomains": true + }, + { + "host": "megaplan.cz", + "include_subdomains": true + }, + { + "host": "megaplan.ru", + "include_subdomains": true + }, + { + "host": "miketabor.com", + "include_subdomains": true + }, + { + "host": "mineover.es", + "include_subdomains": true + }, + { + "host": "mokote.com", + "include_subdomains": true + }, + { + "host": "mr-hosting.com", + "include_subdomains": true + }, + { + "host": "msa-aesch.ch", + "include_subdomains": true + }, + { + "host": "mutamatic.com", + "include_subdomains": true + }, + { + "host": "nymphetomania.net", + "include_subdomains": true + }, + { + "host": "offshore-firma.org", + "include_subdomains": true + }, + { + "host": "openacademies.com", + "include_subdomains": true + }, + { + "host": "phoenix.dj", + "include_subdomains": true + }, + { + "host": "pmg-offshore-company.com", + "include_subdomains": true + }, + { + "host": "pmg-purchase.com", + "include_subdomains": true + }, + { + "host": "pmg-purchase.net", + "include_subdomains": true + }, + { + "host": "polypho.nyc", + "include_subdomains": true + }, + { + "host": "puiterwijk.org", + "include_subdomains": true + }, + { + "host": "redletter.link", + "include_subdomains": true + }, + { + "host": "reg.ru", + "include_subdomains": true + }, + { + "host": "release-monitoring.org", + "include_subdomains": true + }, + { + "host": "rika.me", + "include_subdomains": true + }, + { + "host": "scrambler.in", + "include_subdomains": true + }, + { + "host": "sjoorm.com", + "include_subdomains": true + }, + { + "host": "survivalmonkey.com", + "include_subdomains": true + }, + { + "host": "sychov.pro", + "include_subdomains": true + }, + { + "host": "terrty.net", + "include_subdomains": true + }, + { + "host": "thebimhub.com", + "include_subdomains": true + }, + { + "host": "tmtopup.com", + "include_subdomains": true + }, + { + "host": "uae-company-service.com", + "include_subdomains": true + }, + { + "host": "wherephoto.com", + "include_subdomains": true + }, + { + "host": "wills.co.tt", + "include_subdomains": true + }, + { + "host": "wondershift.biz", + "include_subdomains": true + }, + { + "host": "wzrd.in", + "include_subdomains": true + }, + { + "host": "xplore-dna.net", + "include_subdomains": true + }, + { + "host": "xuntier.ch", + "include_subdomains": true + }, + { + "host": "yanovich.net", + "include_subdomains": true + }, + { + "host": "yaporn.tv", + "include_subdomains": true + }, + { + "host": "yorcom.nl", + "include_subdomains": true + }, + { + "host": "admin.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "id.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "kojipkgs.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "apps.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "badges.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "ask.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "admin.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "apps.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "ask.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "badges.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "darkserver.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "darkserver.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "geoip.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "geoip.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "lists.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "lists.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "qa.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "qa.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "redirect.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "redirect.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "taskotron.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "taskotron.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "translate.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "translate.stg.fedoraproject.org", + "include_subdomains": true + }, + { + "host": "landscape.canonical.com", + "include_subdomains": true + }, + { + "host": "auth.mail.ru", + "include_subdomains": true + }, + { + "host": "e.mail.ru", + "include_subdomains": true + }, + { + "host": "touch.mail.ru", + "include_subdomains": true + }, + { + "host": "light.mail.ru", + "include_subdomains": true + }, + { + "host": "m.mail.ru", + "include_subdomains": true + }, + { + "host": "arty.name", + "include_subdomains": true + }, + { + "host": "7183.org", + "include_subdomains": true + }, + { + "host": "8ack.de", + "include_subdomains": true + }, + { + "host": "9point6.com", + "include_subdomains": true + }, + { + "host": "altmv.com", + "include_subdomains": true + }, + { + "host": "andere-gedanken.net", + "include_subdomains": true + }, + { + "host": "andymartin.cc", + "include_subdomains": true + }, + { + "host": "antipolygraph.org", + "include_subdomains": true + }, + { + "host": "areafiftylan.nl", + "include_subdomains": true + }, + { + "host": "aroonchande.com", + "include_subdomains": true + }, + { + "host": "atc.io", + "include_subdomains": true + }, + { + "host": "auto4trade.nl", + "include_subdomains": true + }, + { + "host": "bagelsbakery.com", + "include_subdomains": true + }, + { + "host": "bcm.com.au", + "include_subdomains": true + }, + { + "host": "beercandle.com", + "include_subdomains": true + }, + { + "host": "billigssl.dk", + "include_subdomains": true + }, + { + "host": "bonitabrazilian.co.nz", + "include_subdomains": true + }, + { + "host": "brandbuilderwebsites.com", + "include_subdomains": true + }, + { + "host": "breeswish.org", + "include_subdomains": true + }, + { + "host": "bundaberg.com", + "include_subdomains": true + }, + { + "host": "bustimes.org", + "include_subdomains": true + }, + { + "host": "calories.org", + "include_subdomains": true + }, + { + "host": "capitaltg.com", + "include_subdomains": true + }, + { + "host": "chartstoffarm.de", + "include_subdomains": true + }, + { + "host": "chrisirwin.ca", + "include_subdomains": true + }, + { + "host": "classdojo.com", + "include_subdomains": true + }, + { + "host": "consumersentinel.gov", + "include_subdomains": true + }, + { + "host": "cybozulive.com", + "include_subdomains": true + }, + { + "host": "darlo.co.uk", + "include_subdomains": true + }, + { + "host": "datasnitch.co.uk", + "include_subdomains": true + }, + { + "host": "dn42.us", + "include_subdomains": true + }, + { + "host": "dnsman.se", + "include_subdomains": true + }, + { + "host": "dreamsforabetterworld.com.au", + "include_subdomains": true + }, + { + "host": "ectora.com", + "include_subdomains": true + }, + { + "host": "elliquiy.com", + "include_subdomains": true + }, + { + "host": "florian-lillpopp.de", + "include_subdomains": true + }, + { + "host": "florianlillpopp.de", + "include_subdomains": true + }, + { + "host": "geekandi.com", + "include_subdomains": true + }, + { + "host": "heute-kaufen.de", + "include_subdomains": true + }, + { + "host": "hushfile.it", + "include_subdomains": true + }, + { + "host": "interasistmen.se", + "include_subdomains": true + }, + { + "host": "johannes.io", + "include_subdomains": true + }, + { + "host": "kamikano.com", + "include_subdomains": true + }, + { + "host": "kintone.com", + "include_subdomains": true + }, + { + "host": "koen.io", + "include_subdomains": true + }, + { + "host": "koenrouwhorst.nl", + "include_subdomains": true + }, + { + "host": "lillpopp.eu", + "include_subdomains": true + }, + { + "host": "linx.li", + "include_subdomains": true + }, + { + "host": "lnx.li", + "include_subdomains": true + }, + { + "host": "madeitwor.se", + "include_subdomains": true + }, + { + "host": "mailmag.net", + "include_subdomains": true + }, + { + "host": "mevs.cz", + "include_subdomains": true + }, + { + "host": "miconcinemas.com", + "include_subdomains": true + }, + { + "host": "mindoktor.se", + "include_subdomains": true + }, + { + "host": "mister.hosting", + "include_subdomains": true + }, + { + "host": "mtau.com", + "include_subdomains": true + }, + { + "host": "myprintcard.de", + "include_subdomains": true + }, + { + "host": "nationalpriorities.org", + "include_subdomains": true + }, + { + "host": "nodari.com.ar", + "include_subdomains": true + }, + { + "host": "nuvini.com", + "include_subdomains": true + }, + { + "host": "nwa.xyz", + "include_subdomains": true + }, + { + "host": "paulschreiber.com", + "include_subdomains": true + }, + { + "host": "philosopherswool.com", + "include_subdomains": true + }, + { + "host": "preissler.co.uk", + "include_subdomains": true + }, + { + "host": "proofwiki.org", + "include_subdomains": true + }, + { + "host": "rawstorieslondon.com", + "include_subdomains": true + }, + { + "host": "reaconverter.com", + "include_subdomains": true + }, + { + "host": "robinadr.com", + "include_subdomains": true + }, + { + "host": "rodosto.com", + "include_subdomains": true + }, + { + "host": "rssr.se", + "include_subdomains": true + }, + { + "host": "rubendv.be", + "include_subdomains": true + }, + { + "host": "scoutdb.ch", + "include_subdomains": true + }, + { + "host": "setuid.io", + "include_subdomains": true + }, + { + "host": "shadex.net", + "include_subdomains": true + }, + { + "host": "sockeye.cc", + "include_subdomains": true + }, + { + "host": "soulogic.com", + "include_subdomains": true + }, + { + "host": "teamnorthgermany.de", + "include_subdomains": true + }, + { + "host": "terraelectronica.ru", + "include_subdomains": true + }, + { + "host": "themoep.at", + "include_subdomains": true + }, + { + "host": "torquato.de", + "include_subdomains": true + }, + { + "host": "utleieplassen.no", + "include_subdomains": true + }, + { + "host": "vijos.org", + "include_subdomains": true + }, + { + "host": "vyncke.org", + "include_subdomains": true + }, + { + "host": "webeau.com", + "include_subdomains": true + }, + { + "host": "wifirst.net", + "include_subdomains": true + }, + { + "host": "wisv.ch", + "include_subdomains": true + }, + { + "host": "zapier.com", + "include_subdomains": true + }, + { + "host": "56ct.com", + "include_subdomains": true + }, + { + "host": "5apps.com", + "include_subdomains": true + }, + { + "host": "abmahnhelfer.de", + "include_subdomains": true + }, + { + "host": "adamstas.com", + "include_subdomains": true + }, + { + "host": "akselinurmio.fi", + "include_subdomains": true + }, + { + "host": "al-shami.net", + "include_subdomains": true + }, + { + "host": "alanrickmanflipstable.com", + "include_subdomains": true + }, + { + "host": "ankakaak.com", + "include_subdomains": true + }, + { + "host": "anonym-surfen.de", + "include_subdomains": true + }, + { + "host": "apps-for-fishing.com", + "include_subdomains": true + }, + { + "host": "arteseideias.com.pt", + "include_subdomains": true + }, + { + "host": "athenelive.com", + "include_subdomains": true + }, + { + "host": "aurainfosec.com", + "include_subdomains": true + }, + { + "host": "aurainfosec.com.au", + "include_subdomains": true + }, + { + "host": "auraredeye.com", + "include_subdomains": true + }, + { + "host": "auraredshield.com", + "include_subdomains": true + }, + { + "host": "autoledky.sk", + "include_subdomains": true + }, + { + "host": "bitchan.it", + "include_subdomains": true + }, + { + "host": "bitcoinx.ro", + "include_subdomains": true + }, + { + "host": "blackberrycentral.com", + "include_subdomains": true + }, + { + "host": "bloemendal.me", + "include_subdomains": true + }, + { + "host": "boypoint.de", + "include_subdomains": true + }, + { + "host": "bran.cc", + "include_subdomains": true + }, + { + "host": "burtrum.org", + "include_subdomains": true + }, + { + "host": "casa-su.casa", + "include_subdomains": true + }, + { + "host": "cbhq.net", + "include_subdomains": true + }, + { + "host": "coinbase.com", + "include_subdomains": true + }, + { + "host": "commencepayments.com", + "include_subdomains": true + }, + { + "host": "courtlistener.com", + "include_subdomains": true + }, + { + "host": "cryptopush.com", + "include_subdomains": true + }, + { + "host": "curtacircuitos.com.br", + "include_subdomains": true + }, + { + "host": "danskoferie.dk", + "include_subdomains": true + }, + { + "host": "daylightpirates.org", + "include_subdomains": true + }, + { + "host": "deliverance.co.uk", + "include_subdomains": true + }, + { + "host": "devinfo.net", + "include_subdomains": true + }, + { + "host": "disking.co.uk", + "include_subdomains": true + }, + { + "host": "dubrovskiy.net", + "include_subdomains": true + }, + { + "host": "dyeager.org", + "include_subdomains": true + }, + { + "host": "edix.ru", + "include_subdomains": true + }, + { + "host": "erotische-aanbiedingen.nl", + "include_subdomains": true + }, + { + "host": "esoa.net", + "include_subdomains": true + }, + { + "host": "eva.cz", + "include_subdomains": true + }, + { + "host": "evalesc.com", + "include_subdomains": true + }, + { + "host": "faucetbox.com", + "include_subdomains": true + }, + { + "host": "froggstack.de", + "include_subdomains": true + }, + { + "host": "fx5.de", + "include_subdomains": true + }, + { + "host": "gallery44.org", + "include_subdomains": true + }, + { + "host": "gc.net", + "include_subdomains": true + }, + { + "host": "gnetwork.eu", + "include_subdomains": true + }, + { + "host": "gotowned.org", + "include_subdomains": true + }, + { + "host": "gudini.net", + "include_subdomains": true + }, + { + "host": "gugga.dk", + "include_subdomains": true + }, + { + "host": "herbert.io", + "include_subdomains": true + }, + { + "host": "ijohan.nl", + "include_subdomains": true + }, + { + "host": "imgg.es", + "include_subdomains": true + }, + { + "host": "insighti.org", + "include_subdomains": true + }, + { + "host": "ipmimagazine.com", + "include_subdomains": true + }, + { + "host": "isogram.nl", + "include_subdomains": true + }, + { + "host": "j0s.at", + "include_subdomains": true + }, + { + "host": "jbn.mx", + "include_subdomains": true + }, + { + "host": "jeremyness.com", + "include_subdomains": true + }, + { + "host": "jkb.pics", + "include_subdomains": true + }, + { + "host": "jkbuster.com", + "include_subdomains": true + }, + { + "host": "jrc9.ca", + "include_subdomains": true + }, + { + "host": "kalmar.com", + "include_subdomains": true + }, + { + "host": "kanzashi.com", + "include_subdomains": true + }, + { + "host": "kaufberatung.community", + "include_subdomains": true + }, + { + "host": "kissflow.com", + "include_subdomains": true + }, + { + "host": "kollawat.me", + "include_subdomains": true + }, + { + "host": "lavval.com", + "include_subdomains": true + }, + { + "host": "ledhouse.sk", + "include_subdomains": true + }, + { + "host": "lichtspot.de", + "include_subdomains": true + }, + { + "host": "mall.cz", + "include_subdomains": true + }, + { + "host": "mall.hu", + "include_subdomains": true + }, + { + "host": "mall.pl", + "include_subdomains": true + }, + { + "host": "mall.sk", + "include_subdomains": true + }, + { + "host": "malwre.io", + "include_subdomains": true + }, + { + "host": "markayapilandirma.com", + "include_subdomains": true + }, + { + "host": "markhaehnel.de", + "include_subdomains": true + }, + { + "host": "mattfin.ch", + "include_subdomains": true + }, + { + "host": "mattsvensson.com", + "include_subdomains": true + }, + { + "host": "mehmetince.net", + "include_subdomains": true + }, + { + "host": "mh-bloemen.co.jp", + "include_subdomains": true + }, + { + "host": "mimovrste.com", + "include_subdomains": true + }, + { + "host": "mitell.jp", + "include_subdomains": true + }, + { + "host": "mittenhacks.com", + "include_subdomains": true + }, + { + "host": "mnemotiv.com", + "include_subdomains": true + }, + { + "host": "munuc.org", + "include_subdomains": true + }, + { + "host": "mustika.cf", + "include_subdomains": true + }, + { + "host": "mvsecurity.nl", + "include_subdomains": true + }, + { + "host": "nachsendeauftrag.net", + "include_subdomains": true + }, + { + "host": "nan.zone", + "include_subdomains": true + }, + { + "host": "nbl.org.tw", + "include_subdomains": true + }, + { + "host": "nctx.co.uk", + "include_subdomains": true + }, + { + "host": "nemovement.org", + "include_subdomains": true + }, + { + "host": "newkaliningrad.ru", + "include_subdomains": true + }, + { + "host": "noemax.com", + "include_subdomains": true + }, + { + "host": "nsboutique.com", + "include_subdomains": true + }, + { + "host": "ohling.org", + "include_subdomains": true + }, + { + "host": "orcahq.com", + "include_subdomains": true + }, + { + "host": "pasta-factory.co.il", + "include_subdomains": true + }, + { + "host": "pclob.gov", + "include_subdomains": true + }, + { + "host": "plzenskybarcamp.cz", + "include_subdomains": true + }, + { + "host": "ponythread.com", + "include_subdomains": true + }, + { + "host": "popcorntime.ws", + "include_subdomains": true + }, + { + "host": "ptn.moscow", + "include_subdomains": true + }, + { + "host": "radiormi.com", + "include_subdomains": true + }, + { + "host": "renem.net", + "include_subdomains": true + }, + { + "host": "richiemail.net", + "include_subdomains": true + }, + { + "host": "ricochet.im", + "include_subdomains": true + }, + { + "host": "roman-pavlik.cz", + "include_subdomains": true + }, + { + "host": "roots.io", + "include_subdomains": true + }, + { + "host": "royalacademy.org.uk", + "include_subdomains": true + }, + { + "host": "rubecodeberg.com", + "include_subdomains": true + }, + { + "host": "sabahattin-gucukoglu.com", + "include_subdomains": true + }, + { + "host": "sagerus.com", + "include_subdomains": true + }, + { + "host": "sageth.com", + "include_subdomains": true + }, + { + "host": "samfunnet.no", + "include_subdomains": true + }, + { + "host": "saulchristie.com", + "include_subdomains": true + }, + { + "host": "secretserveronline.com", + "include_subdomains": true + }, + { + "host": "securedrop.org", + "include_subdomains": true + }, + { + "host": "sigterm.sh", + "include_subdomains": true + }, + { + "host": "sleio.com", + "include_subdomains": true + }, + { + "host": "souki.cz", + "include_subdomains": true + }, + { + "host": "speedcounter.net", + "include_subdomains": true + }, + { + "host": "stesti.cz", + "include_subdomains": true + }, + { + "host": "stevegrav.es", + "include_subdomains": true + }, + { + "host": "stillyarts.com", + "include_subdomains": true + }, + { + "host": "svager.cz", + "include_subdomains": true + }, + { + "host": "taglondon.org", + "include_subdomains": true + }, + { + "host": "tandarts-haarlem.nl", + "include_subdomains": true + }, + { + "host": "tdrs.info", + "include_subdomains": true + }, + { + "host": "teachforcanada.ca", + "include_subdomains": true + }, + { + "host": "techllage.com", + "include_subdomains": true + }, + { + "host": "techloaner.com", + "include_subdomains": true + }, + { + "host": "theescapistswiki.com", + "include_subdomains": true + }, + { + "host": "therapyportal.com", + "include_subdomains": true + }, + { + "host": "tirex.media", + "include_subdomains": true + }, + { + "host": "titties.ml", + "include_subdomains": true + }, + { + "host": "tomharling.co.uk", + "include_subdomains": true + }, + { + "host": "tomharling.uk", + "include_subdomains": true + }, + { + "host": "toptexture.com", + "include_subdomains": true + }, + { + "host": "tox.im", + "include_subdomains": true + }, + { + "host": "traas.org", + "include_subdomains": true + }, + { + "host": "trashnothing.com", + "include_subdomains": true + }, + { + "host": "tuturulianda.com", + "include_subdomains": true + }, + { + "host": "ucfirst.nl", + "include_subdomains": true + }, + { + "host": "unitedadmins.com", + "include_subdomains": true + }, + { + "host": "unknownphenomena.net", + "include_subdomains": true + }, + { + "host": "uptrends.de", + "include_subdomains": true + }, + { + "host": "utilityapi.com", + "include_subdomains": true + }, + { + "host": "welpy.com", + "include_subdomains": true + }, + { + "host": "wesleyharris.ca", + "include_subdomains": true + }, + { + "host": "resources.flowfinity.com", + "include_subdomains": true + }, + { + "host": "2600hq.com", + "include_subdomains": true + }, + { + "host": "301.website", + "include_subdomains": true + }, + { + "host": "alza.cz", + "include_subdomains": true + }, + { + "host": "armytricka.cz", + "include_subdomains": true + }, + { + "host": "astaxi.net", + "include_subdomains": true + }, + { + "host": "bradkovach.com", + "include_subdomains": true + }, + { + "host": "crypto.graphics", + "include_subdomains": true + }, + { + "host": "cryptography.io", + "include_subdomains": true + }, + { + "host": "danielalvarez.net", + "include_subdomains": true + }, + { + "host": "danonsecurity.com", + "include_subdomains": true + }, + { + "host": "darknode.in", + "include_subdomains": true + }, + { + "host": "davidmcevoy.org.uk", + "include_subdomains": true + }, + { + "host": "diedrich.co", + "include_subdomains": true + }, + { + "host": "domainkauf.de", + "include_subdomains": true + }, + { + "host": "emptypath.com", + "include_subdomains": true + }, + { + "host": "eromixx.com", + "include_subdomains": true + }, + { + "host": "ezequiel-garzon.com", + "include_subdomains": true + }, + { + "host": "ezequiel-garzon.net", + "include_subdomains": true + }, + { + "host": "fa-works.com", + "include_subdomains": true + }, + { + "host": "flagspot.net", + "include_subdomains": true + }, + { + "host": "getmango.com", + "include_subdomains": true + }, + { + "host": "gokmenguresci.com", + "include_subdomains": true + }, + { + "host": "goodwin43.ru", + "include_subdomains": true + }, + { + "host": "gotspot.com", + "include_subdomains": true + }, + { + "host": "gra2.com", + "include_subdomains": true + }, + { + "host": "hledejpravnika.cz", + "include_subdomains": true + }, + { + "host": "ilikerainbows.co", + "include_subdomains": true + }, + { + "host": "indiecert.net", + "include_subdomains": true + }, + { + "host": "irmag.ru", + "include_subdomains": true + }, + { + "host": "johnmichel.org", + "include_subdomains": true + }, + { + "host": "jonpads.com", + "include_subdomains": true + }, + { + "host": "keeleysam.me", + "include_subdomains": true + }, + { + "host": "krouzkyliduska.cz", + "include_subdomains": true + }, + { + "host": "lapetition.be", + "include_subdomains": true + }, + { + "host": "maartenvandekamp.nl", + "include_subdomains": true + }, + { + "host": "mcard.vn", + "include_subdomains": true + }, + { + "host": "mccrypto.de", + "include_subdomains": true + }, + { + "host": "mcnext.net", + "include_subdomains": true + }, + { + "host": "micropple.net", + "include_subdomains": true + }, + { + "host": "munki.org", + "include_subdomains": true + }, + { + "host": "netbox.cc", + "include_subdomains": true + }, + { + "host": "olivierlemoal.fr", + "include_subdomains": true + }, + { + "host": "petplum.com", + "include_subdomains": true + }, + { + "host": "picsto.re", + "include_subdomains": true + }, + { + "host": "pirateproxy.sx", + "include_subdomains": true + }, + { + "host": "proxybay.info", + "include_subdomains": true + }, + { + "host": "red-t-shirt.ru", + "include_subdomains": true + }, + { + "host": "siewert-kau.de", + "include_subdomains": true + }, + { + "host": "skeeley.com", + "include_subdomains": true + }, + { + "host": "soia.ca", + "include_subdomains": true + }, + { + "host": "suos.io", + "include_subdomains": true + }, + { + "host": "syzygy-tables.info", + "include_subdomains": true + }, + { + "host": "todoist.com", + "include_subdomains": true + }, + { + "host": "twofactorauth.org", + "include_subdomains": true + }, + { + "host": "vox.vg", + "include_subdomains": true + }, + { + "host": "walnutgaming.com", + "include_subdomains": true + }, + { + "host": "webrebels.org", + "include_subdomains": true + }, + { + "host": "widememory.com", + "include_subdomains": true + }, + { + "host": "withustrading.com", + "include_subdomains": true + }, + { + "host": "wvr-law.de", + "include_subdomains": true + }, + { + "host": "wzyboy.org", + "include_subdomains": true + }, + { + "host": "xenesisziarovky.sk", + "include_subdomains": true + }, + { + "host": "xf-liam.com", + "include_subdomains": true + }, + { + "host": "yksityisyydensuoja.fi", + "include_subdomains": true + }, + { + "host": "yokeepo.com", + "include_subdomains": true + }, + { + "host": "zravypapir.cz", + "include_subdomains": true + }, + { + "host": "healthcare.gov", + "include_subdomains": false + }, + { + "host": "www.healthcare.gov", + "include_subdomains": false + }, + { + "host": "47ronin.com", + "include_subdomains": true + }, + { + "host": "acuica.co.uk", + "include_subdomains": true + }, + { + "host": "advanced-online.eu", + "include_subdomains": true + }, + { + "host": "arbitrary.ch", + "include_subdomains": true + }, + { + "host": "bidon.ca", + "include_subdomains": true + }, + { + "host": "boiseonlinemall.com", + "include_subdomains": true + }, + { + "host": "cake.care", + "include_subdomains": true + }, + { + "host": "cdlcenter.com", + "include_subdomains": true + }, + { + "host": "climaprecio.es", + "include_subdomains": true + }, + { + "host": "coding.net", + "include_subdomains": true + }, + { + "host": "covenantoftheriver.org", + "include_subdomains": true + }, + { + "host": "danw.io", + "include_subdomains": true + }, + { + "host": "defcon.org", + "include_subdomains": true + }, + { + "host": "digital1st.co.uk", + "include_subdomains": true + }, + { + "host": "dragons-of-highlands.cz", + "include_subdomains": true + }, + { + "host": "enskat.de", + "include_subdomains": true + }, + { + "host": "enskatson-sippe.de", + "include_subdomains": true + }, + { + "host": "eveshamglass.co.uk", + "include_subdomains": true + }, + { + "host": "firebirdrangecookers.com", + "include_subdomains": true + }, + { + "host": "fitkram.cz", + "include_subdomains": true + }, + { + "host": "gambit.pro", + "include_subdomains": true + }, + { + "host": "gambitnash.com", + "include_subdomains": true + }, + { + "host": "ge3k.net", + "include_subdomains": true + }, + { + "host": "hboeck.de", + "include_subdomains": true + }, + { + "host": "hozana.si", + "include_subdomains": true + }, + { + "host": "indovinabank.com.vn", + "include_subdomains": true + }, + { + "host": "ipomue.com", + "include_subdomains": true + }, + { + "host": "ipsec.pl", + "include_subdomains": true + }, + { + "host": "jamesdoylephoto.com", + "include_subdomains": true + }, + { + "host": "jpbike.cz", + "include_subdomains": true + }, + { + "host": "kaneo-gmbh.de", + "include_subdomains": true + }, + { + "host": "kedarastudios.com", + "include_subdomains": true + }, + { + "host": "livekaarten.nl", + "include_subdomains": true + }, + { + "host": "lookzook.com", + "include_subdomains": true + }, + { + "host": "masters.black", + "include_subdomains": true + }, + { + "host": "medallia.io", + "include_subdomains": true + }, + { + "host": "mijn-email.org", + "include_subdomains": true + }, + { + "host": "mindcoding.ro", + "include_subdomains": true + }, + { + "host": "mironet.cz", + "include_subdomains": true + }, + { + "host": "miss-inventory.co.uk", + "include_subdomains": true + }, + { + "host": "nayahe.ru", + "include_subdomains": true + }, + { + "host": "nicolaw.uk", + "include_subdomains": true + }, + { + "host": "nopex.no", + "include_subdomains": true + }, + { + "host": "passphrase.today", + "include_subdomains": true + }, + { + "host": "pollpodium.nl", + "include_subdomains": true + }, + { + "host": "rid-wan.com", + "include_subdomains": true + }, + { + "host": "roan24.pl", + "include_subdomains": true + }, + { + "host": "rusadmin.biz", + "include_subdomains": true + }, + { + "host": "scotthel.me", + "include_subdomains": true + }, + { + "host": "smith.is", + "include_subdomains": true + }, + { + "host": "sneezry.com", + "include_subdomains": true + }, + { + "host": "subeesu.com", + "include_subdomains": true + }, + { + "host": "tempus-aquilae.de", + "include_subdomains": true + }, + { + "host": "terraweb.net", + "include_subdomains": true + }, + { + "host": "theamp.com", + "include_subdomains": true + }, + { + "host": "theunitedstates.io", + "include_subdomains": true + }, + { + "host": "tomrichards.net", + "include_subdomains": true + }, + { + "host": "tuitle.com", + "include_subdomains": true + }, + { + "host": "tuxplace.nl", + "include_subdomains": true + }, + { + "host": "vechkasov.ru", + "include_subdomains": true + }, + { + "host": "walnutgaming.co.uk", + "include_subdomains": true + }, + { + "host": "yafuoku.ru", + "include_subdomains": true + }, + { + "host": "youdowell.com", + "include_subdomains": true + }, + { + "host": "188trafalgar.ca", + "include_subdomains": true + }, + { + "host": "314chan.org", + "include_subdomains": true + }, + { + "host": "aerolog.co", + "include_subdomains": true + }, + { + "host": "aeyoun.com", + "include_subdomains": true + }, + { + "host": "afp548.tk", + "include_subdomains": true + }, + { + "host": "afrodigital.uk", + "include_subdomains": true + }, + { + "host": "agrios.de", + "include_subdomains": true + }, + { + "host": "alza.de", + "include_subdomains": true + }, + { + "host": "alza.sk", + "include_subdomains": true + }, + { + "host": "alzashop.com", + "include_subdomains": true + }, + { + "host": "ben-energy.com", + "include_subdomains": true + }, + { + "host": "buiko.com", + "include_subdomains": true + }, + { + "host": "cdt.org", + "include_subdomains": true + }, + { + "host": "cheesetart.my", + "include_subdomains": true + }, + { + "host": "climateinteractive.org", + "include_subdomains": true + }, + { + "host": "costablancavoorjou.com", + "include_subdomains": true + }, + { + "host": "cracker.in.th", + "include_subdomains": true + }, + { + "host": "dohosting.ru", + "include_subdomains": true + }, + { + "host": "donmez.uk", + "include_subdomains": true + }, + { + "host": "ecake.in", + "include_subdomains": true + }, + { + "host": "ego4u.com", + "include_subdomains": true + }, + { + "host": "ego4u.de", + "include_subdomains": true + }, + { + "host": "etoprekrasno.ru", + "include_subdomains": true + }, + { + "host": "fish-hook.ru", + "include_subdomains": true + }, + { + "host": "fniephaus.com", + "include_subdomains": true + }, + { + "host": "forgix.com", + "include_subdomains": true + }, + { + "host": "fuzzing-project.org", + "include_subdomains": true + }, + { + "host": "gameserver-sponsor.de", + "include_subdomains": true + }, + { + "host": "genuxtsg.com", + "include_subdomains": true + }, + { + "host": "globalittech.com", + "include_subdomains": true + }, + { + "host": "gregorytlee.me", + "include_subdomains": true + }, + { + "host": "grocock.me.uk", + "include_subdomains": true + }, + { + "host": "groszek.pl", + "include_subdomains": true + }, + { + "host": "guru-naradi.cz", + "include_subdomains": true + }, + { + "host": "gwijaya.com", + "include_subdomains": true + }, + { + "host": "i10z.com", + "include_subdomains": true + }, + { + "host": "identitylabs.uk", + "include_subdomains": true + }, + { + "host": "ieval.ro", + "include_subdomains": true + }, + { + "host": "influxus.com", + "include_subdomains": true + }, + { + "host": "iostips.ru", + "include_subdomains": true + }, + { + "host": "jetaprices.com", + "include_subdomains": true + }, + { + "host": "jwnotifier.org", + "include_subdomains": true + }, + { + "host": "karaoketonight.com", + "include_subdomains": true + }, + { + "host": "keeley.gq", + "include_subdomains": true + }, + { + "host": "keeley.ml", + "include_subdomains": true + }, + { + "host": "keybase.io", + "include_subdomains": true + }, + { + "host": "keycom.co.uk", + "include_subdomains": true + }, + { + "host": "kinganywhere.eu", + "include_subdomains": true + }, + { + "host": "ks-watch.de", + "include_subdomains": true + }, + { + "host": "leakedminecraft.net", + "include_subdomains": true + }, + { + "host": "leonax.net", + "include_subdomains": true + }, + { + "host": "linorman1997.me", + "include_subdomains": true + }, + { + "host": "metrobriefs.com", + "include_subdomains": true + }, + { + "host": "minora.io", + "include_subdomains": true + }, + { + "host": "musi.cx", + "include_subdomains": true + }, + { + "host": "mykontool.de", + "include_subdomains": true + }, + { + "host": "nostraforma.com", + "include_subdomains": true + }, + { + "host": "nzb.cat", + "include_subdomains": true + }, + { + "host": "orhideous.name", + "include_subdomains": true + }, + { + "host": "osquery.io", + "include_subdomains": true + }, + { + "host": "ramsor-gaming.de", + "include_subdomains": true + }, + { + "host": "robertof.ovh", + "include_subdomains": true + }, + { + "host": "robinsonyu.com", + "include_subdomains": true + }, + { + "host": "scrap.tf", + "include_subdomains": true + }, + { + "host": "sistemy48.ru", + "include_subdomains": true + }, + { + "host": "slack-files.com", + "include_subdomains": true + }, + { + "host": "slse.ca", + "include_subdomains": true + }, + { + "host": "starapple.nl", + "include_subdomains": true + }, + { + "host": "stirling.co", + "include_subdomains": true + }, + { + "host": "stormhub.org", + "include_subdomains": true + }, + { + "host": "taken.pl", + "include_subdomains": true + }, + { + "host": "teamupturn.com", + "include_subdomains": true + }, + { + "host": "technotonic.com.au", + "include_subdomains": true + }, + { + "host": "thca.ca", + "include_subdomains": true + }, + { + "host": "thouni.de", + "include_subdomains": true + }, + { + "host": "timotrans.de", + "include_subdomains": true + }, + { + "host": "timotrans.eu", + "include_subdomains": true + }, + { + "host": "tollsjekk.no", + "include_subdomains": true + }, + { + "host": "tom.horse", + "include_subdomains": true + }, + { + "host": "tradingcentre.com.au", + "include_subdomains": true + }, + { + "host": "ts3.consulting", + "include_subdomains": true + }, + { + "host": "tuamoronline.com", + "include_subdomains": true + }, + { + "host": "unravel.ie", + "include_subdomains": true + }, + { + "host": "wownmedia.com", + "include_subdomains": true + }, + { + "host": "xtrim.ru", + "include_subdomains": true + }, + { + "host": "yamaken.jp", + "include_subdomains": true + }, + { + "host": "yenniferallulli.com", + "include_subdomains": true + }, + { + "host": "yenniferallulli.de", + "include_subdomains": true + }, + { + "host": "yenniferallulli.es", + "include_subdomains": true + }, + { + "host": "yenniferallulli.moda", + "include_subdomains": true + }, + { + "host": "yenniferallulli.nl", + "include_subdomains": true + }, + { + "host": "akachanikuji.com", + "include_subdomains": true + }, + { + "host": "amaforums.org", + "include_subdomains": true + }, + { + "host": "amdouglas.uk", + "include_subdomains": true + }, + { + "host": "anadoluefessk.org", + "include_subdomains": true + }, + { + "host": "axka.com", + "include_subdomains": true + }, + { + "host": "bitcoin.de", + "include_subdomains": true + }, + { + "host": "blablacar.co.uk", + "include_subdomains": true + }, + { + "host": "blablacar.com", + "include_subdomains": true + }, + { + "host": "blablacar.com.tr", + "include_subdomains": true + }, + { + "host": "blablacar.com.ua", + "include_subdomains": true + }, + { + "host": "blablacar.de", + "include_subdomains": true + }, + { + "host": "blablacar.es", + "include_subdomains": true + }, + { + "host": "blablacar.fr", + "include_subdomains": true + }, + { + "host": "blablacar.hr", + "include_subdomains": true + }, + { + "host": "blablacar.hu", + "include_subdomains": true + }, + { + "host": "blablacar.in", + "include_subdomains": true + }, + { + "host": "blablacar.it", + "include_subdomains": true + }, + { + "host": "blablacar.mx", + "include_subdomains": true + }, + { + "host": "blablacar.nl", + "include_subdomains": true + }, + { + "host": "blablacar.pl", + "include_subdomains": true + }, + { + "host": "blablacar.pt", + "include_subdomains": true + }, + { + "host": "blablacar.ro", + "include_subdomains": true + }, + { + "host": "blablacar.rs", + "include_subdomains": true + }, + { + "host": "blablacar.ru", + "include_subdomains": true + }, + { + "host": "canhazip.com", + "include_subdomains": true + }, + { + "host": "carbonmade.com", + "include_subdomains": true + }, + { + "host": "collinmbarrett.com", + "include_subdomains": true + }, + { + "host": "coloradocomputernetworking.net", + "include_subdomains": true + }, + { + "host": "copperhead.co", + "include_subdomains": true + }, + { + "host": "covoiturage.fr", + "include_subdomains": true + }, + { + "host": "csacongress.org", + "include_subdomains": true + }, + { + "host": "czakey.net", + "include_subdomains": true + }, + { + "host": "czk.mk", + "include_subdomains": true + }, + { + "host": "dpsg-roden.de", + "include_subdomains": true + }, + { + "host": "ducohosting.com", + "include_subdomains": true + }, + { + "host": "eatsleeprepeat.net", + "include_subdomains": true + }, + { + "host": "ethercalc.com", + "include_subdomains": true + }, + { + "host": "ethercalc.org", + "include_subdomains": true + }, + { + "host": "fluxfingers.net", + "include_subdomains": true + }, + { + "host": "getbambu.com", + "include_subdomains": true + }, + { + "host": "haber1903.com", + "include_subdomains": true + }, + { + "host": "initrd.net", + "include_subdomains": true + }, + { + "host": "integromat.com", + "include_subdomains": true + }, + { + "host": "lookyman.net", + "include_subdomains": true + }, + { + "host": "lore.azurewebsites.net", + "include_subdomains": true + }, + { + "host": "medovea.ru", + "include_subdomains": true + }, + { + "host": "novacoast.com", + "include_subdomains": true + }, + { + "host": "ohnemusik.com", + "include_subdomains": true + }, + { + "host": "patriksimek.cz", + "include_subdomains": true + }, + { + "host": "pcel.com", + "include_subdomains": true + }, + { + "host": "postfinance.ch", + "include_subdomains": true + }, + { + "host": "preloaded-hsts.badssl.com", + "include_subdomains": true + }, + { + "host": "raymii.org", + "include_subdomains": true + }, + { + "host": "research.md", + "include_subdomains": true + }, + { + "host": "rubyshop.nl", + "include_subdomains": true + }, + { + "host": "sec.gd", + "include_subdomains": true + }, + { + "host": "servertastic.com", + "include_subdomains": true + }, + { + "host": "sh-network.de", + "include_subdomains": true + }, + { + "host": "sufix.cz", + "include_subdomains": true + }, + { + "host": "tallr.se", + "include_subdomains": true + }, + { + "host": "thehiddenbay.net", + "include_subdomains": true + }, + { + "host": "tinkertry.com", + "include_subdomains": true + }, + { + "host": "vasanth.org", + "include_subdomains": true + }, + { + "host": "voicesuk.co.uk", + "include_subdomains": true + }, + { + "host": "vserver-preis-vergleich.de", + "include_subdomains": true + }, + { + "host": "whitestagforge.com", + "include_subdomains": true + }, + { + "host": "x.io", + "include_subdomains": true + }, + { + "host": "zalan.do", + "include_subdomains": true + }, + { + "host": "zarooba.com", + "include_subdomains": true + }, + { + "host": "1000minds.com", + "include_subdomains": true + }, + { + "host": "1a-jva.de", + "include_subdomains": true + }, + { + "host": "300651.ru", + "include_subdomains": true + }, + { + "host": "3do3dont.com", + "include_subdomains": true + }, + { + "host": "4g-server.eu", + "include_subdomains": true + }, + { + "host": "aircomms.com", + "include_subdomains": true + }, + { + "host": "alexgaynor.net", + "include_subdomains": true + }, + { + "host": "allinonecyprus.com", + "include_subdomains": true + }, + { + "host": "alphabit-secure.com", + "include_subdomains": true + }, + { + "host": "apple-watch-zubehoer.de", + "include_subdomains": true + }, + { + "host": "baff.lu", + "include_subdomains": true + }, + { + "host": "benchling.com", + "include_subdomains": true + }, + { + "host": "bit-sentinel.com", + "include_subdomains": true + }, + { + "host": "bitnet.io", + "include_subdomains": true + }, + { + "host": "buildkite.com", + "include_subdomains": true + }, + { + "host": "calvin.me", + "include_subdomains": true + }, + { + "host": "cklie.de", + "include_subdomains": true + }, + { + "host": "ckliemann.com", + "include_subdomains": true + }, + { + "host": "ckliemann.net", + "include_subdomains": true + }, + { + "host": "console.support", + "include_subdomains": true + }, + { + "host": "crute.me", + "include_subdomains": true + }, + { + "host": "cycleluxembourg.lu", + "include_subdomains": true + }, + { + "host": "dash-board.jp", + "include_subdomains": true + }, + { + "host": "dekasan.ru", + "include_subdomains": true + }, + { + "host": "doridian.com", + "include_subdomains": true + }, + { + "host": "doridian.de", + "include_subdomains": true + }, + { + "host": "doridian.net", + "include_subdomains": true + }, + { + "host": "doridian.org", + "include_subdomains": true + }, + { + "host": "drtroyhendrickson.com", + "include_subdomains": true + }, + { + "host": "edelsteincosmetic.com", + "include_subdomains": true + }, + { + "host": "edge-cloud.net", + "include_subdomains": true + }, + { + "host": "ellegaard.dk", + "include_subdomains": true + }, + { + "host": "enigmail.net", + "include_subdomains": true + }, + { + "host": "enterdev.co", + "include_subdomains": true + }, + { + "host": "eru.me", + "include_subdomains": true + }, + { + "host": "ezimoeko.net", + "include_subdomains": true + }, + { + "host": "eztv.ch", + "include_subdomains": true + }, + { + "host": "feedthebot.com", + "include_subdomains": true + }, + { + "host": "feminists.co", + "include_subdomains": true + }, + { + "host": "festember.com", + "include_subdomains": true + }, + { + "host": "fidelapp.com", + "include_subdomains": true + }, + { + "host": "floweslawncare.com", + "include_subdomains": true + }, + { + "host": "foxelbox.com", + "include_subdomains": true + }, + { + "host": "fsma.pl", + "include_subdomains": true + }, + { + "host": "getcolor.com", + "include_subdomains": true + }, + { + "host": "getsello.com", + "include_subdomains": true + }, + { + "host": "gheorghesarcov.ga", + "include_subdomains": true + }, + { + "host": "goldendata.io", + "include_subdomains": true + }, + { + "host": "golfscape.com", + "include_subdomains": true + }, + { + "host": "gothamlimo.com", + "include_subdomains": true + }, + { + "host": "grandcapital.id", + "include_subdomains": true + }, + { + "host": "grandcapital.ru", + "include_subdomains": true + }, + { + "host": "gurusupe.com", + "include_subdomains": true + }, + { + "host": "hash-list.com", + "include_subdomains": true + }, + { + "host": "heavystresser.com", + "include_subdomains": true + }, + { + "host": "hicn.gq", + "include_subdomains": true + }, + { + "host": "hobbyspeed.com", + "include_subdomains": true + }, + { + "host": "holymoly.lu", + "include_subdomains": true + }, + { + "host": "ilbuongiorno.it", + "include_subdomains": true + }, + { + "host": "imagr.io", + "include_subdomains": true + }, + { + "host": "infogrfx.com", + "include_subdomains": true + }, + { + "host": "j-lsolutions.com", + "include_subdomains": true + }, + { + "host": "jacobparry.ca", + "include_subdomains": true + }, + { + "host": "jacuzziprozone.com", + "include_subdomains": true + }, + { + "host": "jahliveradio.com", + "include_subdomains": true + }, + { + "host": "jh-media.eu", + "include_subdomains": true + }, + { + "host": "jondevin.com", + "include_subdomains": true + }, + { + "host": "julianmeyer.de", + "include_subdomains": true + }, + { + "host": "kavovary-kava.cz", + "include_subdomains": true + }, + { + "host": "khipu.com", + "include_subdomains": true + }, + { + "host": "kliemann.me", + "include_subdomains": true + }, + { + "host": "kredite24.de", + "include_subdomains": true + }, + { + "host": "labaia.info", + "include_subdomains": true + }, + { + "host": "laukstein.com", + "include_subdomains": true + }, + { + "host": "leanclub.org", + "include_subdomains": true + }, + { + "host": "lence.net", + "include_subdomains": true + }, + { + "host": "lmmtfy.io", + "include_subdomains": true + }, + { + "host": "mafamane.com", + "include_subdomains": true + }, + { + "host": "mercuryamericas.com", + "include_subdomains": true + }, + { + "host": "mobilux.lv", + "include_subdomains": true + }, + { + "host": "musmann.io", + "include_subdomains": true + }, + { + "host": "nanderson.me", + "include_subdomains": true + }, + { + "host": "nerven.se", + "include_subdomains": true + }, + { + "host": "netrelay.email", + "include_subdomains": true + }, + { + "host": "nijm.nl", + "include_subdomains": true + }, + { + "host": "noob-box.net", + "include_subdomains": true + }, + { + "host": "northernmuscle.ca", + "include_subdomains": true + }, + { + "host": "ownmovies.fr", + "include_subdomains": true + }, + { + "host": "pactf.com", + "include_subdomains": true + }, + { + "host": "pap.la", + "include_subdomains": true + }, + { + "host": "phil.tw", + "include_subdomains": true + }, + { + "host": "pi-supply.com", + "include_subdomains": true + }, + { + "host": "pijuice.com", + "include_subdomains": true + }, + { + "host": "piratedb.com", + "include_subdomains": true + }, + { + "host": "piratedot.com", + "include_subdomains": true + }, + { + "host": "prontolight.com", + "include_subdomains": true + }, + { + "host": "proxybay.club", + "include_subdomains": true + }, + { + "host": "proxybay.co", + "include_subdomains": true + }, + { + "host": "quebecmailbox.com", + "include_subdomains": true + }, + { + "host": "refundo.cz", + "include_subdomains": true + }, + { + "host": "refundo.sk", + "include_subdomains": true + }, + { + "host": "rischard.org", + "include_subdomains": true + }, + { + "host": "robtex.com", + "include_subdomains": true + }, + { + "host": "rotunneling.net", + "include_subdomains": true + }, + { + "host": "rpy.xyz", + "include_subdomains": true + }, + { + "host": "sello.com", + "include_subdomains": true + }, + { + "host": "sellocdn.com", + "include_subdomains": true + }, + { + "host": "sidium.de", + "include_subdomains": true + }, + { + "host": "slever.cz", + "include_subdomains": true + }, + { + "host": "sourceway.de", + "include_subdomains": true + }, + { + "host": "stereo.lu", + "include_subdomains": true + }, + { + "host": "sticklerjs.org", + "include_subdomains": true + }, + { + "host": "storedsafe.com", + "include_subdomains": true + }, + { + "host": "stuartbaxter.co", + "include_subdomains": true + }, + { + "host": "t23m-navi.jp", + "include_subdomains": true + }, + { + "host": "tcgrepublic.com", + "include_subdomains": true + }, + { + "host": "temp.pm", + "include_subdomains": true + }, + { + "host": "terrax.info", + "include_subdomains": true + }, + { + "host": "terrax.net", + "include_subdomains": true + }, + { + "host": "thefrozenfire.com", + "include_subdomains": true + }, + { + "host": "thepiratebay.al", + "include_subdomains": true + }, + { + "host": "thumbtack.com", + "include_subdomains": true + }, + { + "host": "timmy.ws", + "include_subdomains": true + }, + { + "host": "tipsyk.ru", + "include_subdomains": true + }, + { + "host": "topshelfguild.com", + "include_subdomains": true + }, + { + "host": "tormentedradio.com", + "include_subdomains": true + }, + { + "host": "tpbproxy.co", + "include_subdomains": true + }, + { + "host": "twolinepassbrewing.com", + "include_subdomains": true + }, + { + "host": "unbanthe.net", + "include_subdomains": true + }, + { + "host": "uow.ninja", + "include_subdomains": true + }, + { + "host": "upitnik.rs", + "include_subdomains": true + }, + { + "host": "uscntalk.com", + "include_subdomains": true + }, + { + "host": "venicerealdeal.com", + "include_subdomains": true + }, + { + "host": "vomitb.in", + "include_subdomains": true + }, + { + "host": "vyplnto.cz", + "include_subdomains": true + }, + { + "host": "webmaniabr.com", + "include_subdomains": true + }, + { + "host": "wettertoertchen.com", + "include_subdomains": true + }, + { + "host": "williamsonshore.com", + "include_subdomains": true + }, + { + "host": "wtfismyip.com", + "include_subdomains": true + }, + { + "host": "xpd.se", + "include_subdomains": true + }, + { + "host": "zbasenem.pl", + "include_subdomains": true + }, + { + "host": "zifb.in", + "include_subdomains": true + }, + { + "host": "zlatosnadno.cz", + "include_subdomains": true + }, + { + "host": "4sqsu.eu", + "include_subdomains": true + }, + { + "host": "abecodes.net", + "include_subdomains": true + }, + { + "host": "abiapp.net", + "include_subdomains": true + }, + { + "host": "adambyers.com", + "include_subdomains": true + }, + { + "host": "aes256.ru", + "include_subdomains": true + }, + { + "host": "akselimedia.fi", + "include_subdomains": true + }, + { + "host": "alaninkenya.org", + "include_subdomains": true + }, + { + "host": "alethearose.com", + "include_subdomains": true + }, + { + "host": "anakros.me", + "include_subdomains": true + }, + { + "host": "andrewimeson.com", + "include_subdomains": true + }, + { + "host": "antoniomarques.eu", + "include_subdomains": true + }, + { + "host": "apachehaus.de", + "include_subdomains": true + }, + { + "host": "apibot.de", + "include_subdomains": true + }, + { + "host": "aponow.de", + "include_subdomains": true + }, + { + "host": "aranycsillag.net", + "include_subdomains": true + }, + { + "host": "arrayify.com", + "include_subdomains": true + }, + { + "host": "auszeit.bio", + "include_subdomains": true + }, + { + "host": "av.de", + "include_subdomains": true + }, + { + "host": "azirevpn.com", + "include_subdomains": true + }, + { + "host": "bardiharborow.com", + "include_subdomains": true + }, + { + "host": "beach-inspector.com", + "include_subdomains": true + }, + { + "host": "biddl.com", + "include_subdomains": true + }, + { + "host": "bigdinosaur.org", + "include_subdomains": true + }, + { + "host": "bownty.dk", + "include_subdomains": true + }, + { + "host": "braineet.com", + "include_subdomains": true + }, + { + "host": "branchtrack.com", + "include_subdomains": true + }, + { + "host": "brks.xyz", + "include_subdomains": true + }, + { + "host": "businesshosting.nl", + "include_subdomains": true + }, + { + "host": "bygningsregistrering.dk", + "include_subdomains": true + }, + { + "host": "bysymphony.com", + "include_subdomains": true + }, + { + "host": "cardoni.net", + "include_subdomains": true + }, + { + "host": "carlosalves.info", + "include_subdomains": true + }, + { + "host": "catnapstudios.com", + "include_subdomains": true + }, + { + "host": "chippy.ch", + "include_subdomains": true + }, + { + "host": "chriswarrick.com", + "include_subdomains": true + }, + { + "host": "chroniclesofgeorge.com", + "include_subdomains": true + }, + { + "host": "clevisto.com", + "include_subdomains": true + }, + { + "host": "cloudpebble.net", + "include_subdomains": true + }, + { + "host": "coindam.com", + "include_subdomains": true + }, + { + "host": "completionist.audio", + "include_subdomains": true + }, + { + "host": "cpvmatch.eu", + "include_subdomains": true + }, + { + "host": "d42.no", + "include_subdomains": true + }, + { + "host": "daknob.net", + "include_subdomains": true + }, + { + "host": "darkengine.io", + "include_subdomains": true + }, + { + "host": "dbgamestudio.com", + "include_subdomains": true + }, + { + "host": "desmaakvanplanten.be", + "include_subdomains": true + }, + { + "host": "devklog.net", + "include_subdomains": true + }, + { + "host": "dnmlab.it", + "include_subdomains": true + }, + { + "host": "dropboxer.net", + "include_subdomains": true + }, + { + "host": "drumbandesperanto.nl", + "include_subdomains": true + }, + { + "host": "eduid.se", + "include_subdomains": true + }, + { + "host": "electromc.com", + "include_subdomains": true + }, + { + "host": "erisrenee.com", + "include_subdomains": true + }, + { + "host": "expoundite.net", + "include_subdomains": true + }, + { + "host": "f2f.cash", + "include_subdomains": true + }, + { + "host": "falconvintners.com", + "include_subdomains": true + }, + { + "host": "fangs.ink", + "include_subdomains": true + }, + { + "host": "fatherhood.gov", + "include_subdomains": true + }, + { + "host": "feen.us", + "include_subdomains": true + }, + { + "host": "ffbans.org", + "include_subdomains": true + }, + { + "host": "fiftyshadesofluca.ml", + "include_subdomains": true + }, + { + "host": "flushstudios.com", + "include_subdomains": true + }, + { + "host": "foodwise.marketing", + "include_subdomains": true + }, + { + "host": "foreignexchangeresource.com", + "include_subdomains": true + }, + { + "host": "fretscha.com", + "include_subdomains": true + }, + { + "host": "fruchthof24.de", + "include_subdomains": true + }, + { + "host": "frusky.de", + "include_subdomains": true + }, + { + "host": "frusky.net", + "include_subdomains": true + }, + { + "host": "fteproxy.org", + "include_subdomains": true + }, + { + "host": "g2g.com", + "include_subdomains": true + }, + { + "host": "gambitprint.com", + "include_subdomains": true + }, + { + "host": "gamercredo.net", + "include_subdomains": true + }, + { + "host": "genuxation.com", + "include_subdomains": true + }, + { + "host": "getnikola.com", + "include_subdomains": true + }, + { + "host": "github.party", + "include_subdomains": true + }, + { + "host": "go-zh.org", + "include_subdomains": true + }, + { + "host": "gopay.cz", + "include_subdomains": true + }, + { + "host": "goshop.cz", + "include_subdomains": true + }, + { + "host": "grigalanzsoftware.com", + "include_subdomains": true + }, + { + "host": "grimm-gastrobedarf.de", + "include_subdomains": true + }, + { + "host": "h2check.org", + "include_subdomains": true + }, + { + "host": "haircrazy.com", + "include_subdomains": true + }, + { + "host": "happyteamlabs.com", + "include_subdomains": true + }, + { + "host": "haveibeenpwned.com", + "include_subdomains": true + }, + { + "host": "heftkaufen.de", + "include_subdomains": true + }, + { + "host": "herzbotschaft.de", + "include_subdomains": true + }, + { + "host": "hiv.gov", + "include_subdomains": true + }, + { + "host": "hs-group.net", + "include_subdomains": true + }, + { + "host": "impex.com.bd", + "include_subdomains": true + }, + { + "host": "informnapalm.org", + "include_subdomains": true + }, + { + "host": "iqualtech.com", + "include_subdomains": true + }, + { + "host": "isimonbrown.co.uk", + "include_subdomains": true + }, + { + "host": "ix8.ru", + "include_subdomains": true + }, + { + "host": "jamesbywater.co.uk", + "include_subdomains": true + }, + { + "host": "jamesbywater.com", + "include_subdomains": true + }, + { + "host": "jamesbywater.me", + "include_subdomains": true + }, + { + "host": "jamesbywater.uk", + "include_subdomains": true + }, + { + "host": "jamielinux.com", + "include_subdomains": true + }, + { + "host": "jogorama.com.br", + "include_subdomains": true + }, + { + "host": "juliansimioni.com", + "include_subdomains": true + }, + { + "host": "justlikethat.hosting", + "include_subdomains": true + }, + { + "host": "kalevlamps.co.uk", + "include_subdomains": true + }, + { + "host": "korinar.com", + "include_subdomains": true + }, + { + "host": "kpdyer.com", + "include_subdomains": true + }, + { + "host": "kredite.sale", + "include_subdomains": true + }, + { + "host": "legoutdesplantes.be", + "include_subdomains": true + }, + { + "host": "lellyboi.ml", + "include_subdomains": true + }, + { + "host": "leninalbertop.com.ve", + "include_subdomains": true + }, + { + "host": "libfte.org", + "include_subdomains": true + }, + { + "host": "limitededitioncomputers.com", + "include_subdomains": true + }, + { + "host": "limitededitionsolutions.com", + "include_subdomains": true + }, + { + "host": "linguaquote.com", + "include_subdomains": true + }, + { + "host": "lloyd-day.me", + "include_subdomains": true + }, + { + "host": "luxwatch.com", + "include_subdomains": true + }, + { + "host": "lymia.moe", + "include_subdomains": true + }, + { + "host": "lyst.co.uk", + "include_subdomains": true + }, + { + "host": "mammaw.com", + "include_subdomains": true + }, + { + "host": "markprof.ru", + "include_subdomains": true + }, + { + "host": "martijnvhoof.nl", + "include_subdomains": true + }, + { + "host": "maximelouet.me", + "include_subdomains": true + }, + { + "host": "me.net.nz", + "include_subdomains": true + }, + { + "host": "mebio.us", + "include_subdomains": true + }, + { + "host": "medtehnika.ua", + "include_subdomains": true + }, + { + "host": "meetingmanage.nl", + "include_subdomains": true + }, + { + "host": "meetings2.com", + "include_subdomains": true + }, + { + "host": "meritz.rocks", + "include_subdomains": true + }, + { + "host": "mertcangokgoz.com", + "include_subdomains": true + }, + { + "host": "mim.properties", + "include_subdomains": true + }, + { + "host": "mjanja.ch", + "include_subdomains": true + }, + { + "host": "mobobe.com", + "include_subdomains": true + }, + { + "host": "modeldimension.com", + "include_subdomains": true + }, + { + "host": "moriz.net", + "include_subdomains": true + }, + { + "host": "mp3juices.is", + "include_subdomains": true + }, + { + "host": "mthode.org", + "include_subdomains": true + }, + { + "host": "multigamecard.com", + "include_subdomains": true + }, + { + "host": "mygretchen.de", + "include_subdomains": true + }, + { + "host": "naiharngym.com", + "include_subdomains": true + }, + { + "host": "ndarville.com", + "include_subdomains": true + }, + { + "host": "nella-project.org", + "include_subdomains": true + }, + { + "host": "nellacms.com", + "include_subdomains": true + }, + { + "host": "nellacms.org", + "include_subdomains": true + }, + { + "host": "nellafw.org", + "include_subdomains": true + }, + { + "host": "nextend.net", + "include_subdomains": true + }, + { + "host": "nmd.so", + "include_subdomains": true + }, + { + "host": "null.tips", + "include_subdomains": true + }, + { + "host": "ocrami.us", + "include_subdomains": true + }, + { + "host": "oguya.ch", + "include_subdomains": true + }, + { + "host": "patechmasters.com", + "include_subdomains": true + }, + { + "host": "payments-reference.org", + "include_subdomains": true + }, + { + "host": "pbprint.ru", + "include_subdomains": true + }, + { + "host": "phcorner.net", + "include_subdomains": true + }, + { + "host": "pieterhordijk.com", + "include_subdomains": true + }, + { + "host": "poedgirl.com", + "include_subdomains": true + }, + { + "host": "poiema.com.sg", + "include_subdomains": true + }, + { + "host": "posttigo.com", + "include_subdomains": true + }, + { + "host": "presidentials2016.com", + "include_subdomains": true + }, + { + "host": "projectascension.io", + "include_subdomains": true + }, + { + "host": "prospo.co", + "include_subdomains": true + }, + { + "host": "purewebmasters.com", + "include_subdomains": true + }, + { + "host": "qualityhomesystems.com", + "include_subdomains": true + }, + { + "host": "quli.nl", + "include_subdomains": true + }, + { + "host": "railgun.ac", + "include_subdomains": true + }, + { + "host": "raydobe.me", + "include_subdomains": true + }, + { + "host": "redlink.de", + "include_subdomains": true + }, + { + "host": "report-uri.io", + "include_subdomains": true + }, + { + "host": "rmmanfredi.com", + "include_subdomains": true + }, + { + "host": "roeper.party", + "include_subdomains": true + }, + { + "host": "roosterpgplus.nl", + "include_subdomains": true + }, + { + "host": "roquecenter.org", + "include_subdomains": true + }, + { + "host": "ryan-goldstein.com", + "include_subdomains": true + }, + { + "host": "safescan.com", + "include_subdomains": true + }, + { + "host": "sarahlicity.co.uk", + "include_subdomains": true + }, + { + "host": "schreibnacht.de", + "include_subdomains": true + }, + { + "host": "screenlight.tv", + "include_subdomains": true + }, + { + "host": "search-one.de", + "include_subdomains": true + }, + { + "host": "securitysnobs.com", + "include_subdomains": true + }, + { + "host": "shamka.ru", + "include_subdomains": true + }, + { + "host": "shanewadleigh.com", + "include_subdomains": true + }, + { + "host": "shasso.com", + "include_subdomains": true + }, + { + "host": "shoprose.ru", + "include_subdomains": true + }, + { + "host": "sitesko.de", + "include_subdomains": true + }, + { + "host": "sizzle.co.uk", + "include_subdomains": true + }, + { + "host": "slope.haus", + "include_subdomains": true + }, + { + "host": "snailing.org", + "include_subdomains": true + }, + { + "host": "snazel.co.uk", + "include_subdomains": true + }, + { + "host": "sny.no", + "include_subdomains": true + }, + { + "host": "soccergif.com", + "include_subdomains": true + }, + { + "host": "soci.ml", + "include_subdomains": true + }, + { + "host": "solihullcarnival.co.uk", + "include_subdomains": true + }, + { + "host": "solihulllionsclub.org.uk", + "include_subdomains": true + }, + { + "host": "soulfulglamour.uk", + "include_subdomains": true + }, + { + "host": "spyroszarzonis.com", + "include_subdomains": true + }, + { + "host": "stablelib.com", + "include_subdomains": true + }, + { + "host": "stereochro.me", + "include_subdomains": true + }, + { + "host": "stewartremodelingadvantage.com", + "include_subdomains": true + }, + { + "host": "streamingmagazin.de", + "include_subdomains": true + }, + { + "host": "talideon.com", + "include_subdomains": true + }, + { + "host": "tdelmas.ovh", + "include_subdomains": true + }, + { + "host": "techhub.ml", + "include_subdomains": true + }, + { + "host": "thecoffeehouse.xyz", + "include_subdomains": true + }, + { + "host": "theweilai.com", + "include_subdomains": true + }, + { + "host": "tonytan.cn", + "include_subdomains": true + }, + { + "host": "topbargains.com.au", + "include_subdomains": true + }, + { + "host": "totem-eshop.cz", + "include_subdomains": true + }, + { + "host": "tribaldos.com", + "include_subdomains": true + }, + { + "host": "tuxgeo.com", + "include_subdomains": true + }, + { + "host": "tzappa.net", + "include_subdomains": true + }, + { + "host": "ubanquity.com", + "include_subdomains": true + }, + { + "host": "uega.net", + "include_subdomains": true + }, + { + "host": "ulabox.com", + "include_subdomains": true + }, + { + "host": "univz.com", + "include_subdomains": true + }, + { + "host": "ust.space", + "include_subdomains": true + }, + { + "host": "vbh2o.com", + "include_subdomains": true + }, + { + "host": "votocek.cz", + "include_subdomains": true + }, + { + "host": "votockova.cz", + "include_subdomains": true + }, + { + "host": "vrtak-cz.net", + "include_subdomains": true + }, + { + "host": "vzk.io", + "include_subdomains": true + }, + { + "host": "wearvr.com", + "include_subdomains": true + }, + { + "host": "webmarketingfestival.it", + "include_subdomains": true + }, + { + "host": "webogram.org", + "include_subdomains": true + }, + { + "host": "webswitch.io", + "include_subdomains": true + }, + { + "host": "wesecom.com", + "include_subdomains": true + }, + { + "host": "when-release.com", + "include_subdomains": true + }, + { + "host": "when.fm", + "include_subdomains": true + }, + { + "host": "wilf1rst.com", + "include_subdomains": true + }, + { + "host": "williamsapiens.com", + "include_subdomains": true + }, + { + "host": "wit.ai", + "include_subdomains": true + }, + { + "host": "worldcubeassociation.org", + "include_subdomains": true + }, + { + "host": "wurzelzwerg.net", + "include_subdomains": true + }, + { + "host": "xcoop.me", + "include_subdomains": true + }, + { + "host": "xho.me", + "include_subdomains": true + }, + { + "host": "xiaolvmu.me", + "include_subdomains": true + }, + { + "host": "yello.website", + "include_subdomains": true + }, + { + "host": "yunzhu.li", + "include_subdomains": true + }, + { + "host": "yunzhu.org", + "include_subdomains": true + }, + { + "host": "zeitpunkt-kulturmagazin.de", + "include_subdomains": true + }, + { + "host": "zentraler-kreditausschuss.de", + "include_subdomains": true + }, + { + "host": "zhang-hao.com", + "include_subdomains": true + }, + { + "host": "acorns.com", + "include_subdomains": true + }, + { + "host": "access-sofia.org", + "include_subdomains": true + }, + { + "host": "4mm.org", + "include_subdomains": true + }, + { + "host": "ada.is", + "include_subdomains": true + }, + { + "host": "adviespuntklokkenluiders.nl", + "include_subdomains": true + }, + { + "host": "abiturma.de", + "include_subdomains": true + }, + { + "host": "alocato.com", + "include_subdomains": true + }, + { + "host": "3473-wiki.de", + "include_subdomains": true + }, + { + "host": "andreasolsson.se", + "include_subdomains": true + }, + { + "host": "2bis10.de", + "include_subdomains": true + }, + { + "host": "abioniere.de", + "include_subdomains": true + }, + { + "host": "4eyes.ch", + "include_subdomains": true + }, + { + "host": "adblockextreme.com", + "include_subdomains": true + }, + { + "host": "auditmatrix.com", + "include_subdomains": true + }, + { + "host": "alex-ross.co.uk", + "include_subdomains": true + }, + { + "host": "akclinics.org", + "include_subdomains": true + }, + { + "host": "aktiv-naturheilmittel.ch", + "include_subdomains": true + }, + { + "host": "belairsewvac.com", + "include_subdomains": true + }, + { + "host": "ball.holdings", + "include_subdomains": true + }, + { + "host": "artegusto.ru", + "include_subdomains": true + }, + { + "host": "backschues.net", + "include_subdomains": true + }, + { + "host": "brianmwaters.net", + "include_subdomains": true + }, + { + "host": "aktiv-naturheilmittel.de", + "include_subdomains": true + }, + { + "host": "aktiv-naturheilmittel.at", + "include_subdomains": true + }, + { + "host": "bitvigor.com", + "include_subdomains": true + }, + { + "host": "augustian-life.cz", + "include_subdomains": true + }, + { + "host": "atlex.nl", + "include_subdomains": true + }, + { + "host": "animesharp.com", + "include_subdomains": true + }, + { + "host": "bochs.info", + "include_subdomains": true + }, + { + "host": "atop.io", + "include_subdomains": true + }, + { + "host": "betaworx.de", + "include_subdomains": true + }, + { + "host": "betaworx.eu", + "include_subdomains": true + }, + { + "host": "calgaryconstructionjobs.com", + "include_subdomains": true + }, + { + "host": "cheapgeekts.com", + "include_subdomains": true + }, + { + "host": "bjornhelmersson.se", + "include_subdomains": true + }, + { + "host": "canyonshoa.com", + "include_subdomains": true + }, + { + "host": "cargobay.net", + "include_subdomains": true + }, + { + "host": "centralvacsunlimited.net", + "include_subdomains": true + }, + { + "host": "chiralsoftware.com", + "include_subdomains": true + }, + { + "host": "bouncyball.eu", + "include_subdomains": true + }, + { + "host": "chrisupjohn.com", + "include_subdomains": true + }, + { + "host": "claimconnect.us", + "include_subdomains": true + }, + { + "host": "ccsys.com", + "include_subdomains": true + }, + { + "host": "ass.org.au", + "include_subdomains": true + }, + { + "host": "bluetenmeer.com", + "include_subdomains": true + }, + { + "host": "codepult.com", + "include_subdomains": true + }, + { + "host": "cesal.net", + "include_subdomains": true + }, + { + "host": "cloudimag.es", + "include_subdomains": true + }, + { + "host": "dealbanana.com", + "include_subdomains": true + }, + { + "host": "collabornation.net", + "include_subdomains": true + }, + { + "host": "cloudflareonazure.com", + "include_subdomains": true + }, + { + "host": "chrismckee.co.uk", + "include_subdomains": true + }, + { + "host": "cobalt.io", + "include_subdomains": true + }, + { + "host": "dealbanana.it", + "include_subdomains": true + }, + { + "host": "cydia-search.io", + "include_subdomains": true + }, + { + "host": "delbart.se", + "include_subdomains": true + }, + { + "host": "dotsiam.com", + "include_subdomains": true + }, + { + "host": "clevertarget.ru", + "include_subdomains": true + }, + { + "host": "connext.de", + "include_subdomains": true + }, + { + "host": "derp.army", + "include_subdomains": true + }, + { + "host": "craftbeerbarn.co.uk", + "include_subdomains": true + }, + { + "host": "ebaymotorssucks.com", + "include_subdomains": true + }, + { + "host": "dymersion.com", + "include_subdomains": true + }, + { + "host": "ctns.de", + "include_subdomains": true + }, + { + "host": "digitalskillswap.com", + "include_subdomains": true + }, + { + "host": "discoveringdocker.com", + "include_subdomains": true + }, + { + "host": "dedeo.tk", + "include_subdomains": true + }, + { + "host": "diablotine.rocks", + "include_subdomains": true + }, + { + "host": "eckel.co", + "include_subdomains": true + }, + { + "host": "disorderboutique.com", + "include_subdomains": true + }, + { + "host": "cesidianroot.eu", + "include_subdomains": true + }, + { + "host": "exceltobarcode.com", + "include_subdomains": true + }, + { + "host": "elvidence.com.au", + "include_subdomains": true + }, + { + "host": "fightr.co", + "include_subdomains": true + }, + { + "host": "eqorg.com", + "include_subdomains": true + }, + { + "host": "dsebastien.net", + "include_subdomains": true + }, + { + "host": "elitegameservers.net", + "include_subdomains": true + }, + { + "host": "dorianmuthig.com", + "include_subdomains": true + }, + { + "host": "ecrimex.net", + "include_subdomains": true + }, + { + "host": "experienceoz.com.au", + "include_subdomains": true + }, + { + "host": "flra.gov", + "include_subdomains": true + }, + { + "host": "fabse.net", + "include_subdomains": true + }, + { + "host": "fotiu.com", + "include_subdomains": true + }, + { + "host": "core.mx", + "include_subdomains": true + }, + { + "host": "fidanza.eu", + "include_subdomains": true + }, + { + "host": "foro.io", + "include_subdomains": true + }, + { + "host": "getspire.com", + "include_subdomains": true + }, + { + "host": "gtmetrix.com", + "include_subdomains": true + }, + { + "host": "hashplex.com", + "include_subdomains": true + }, + { + "host": "footballmapped.com", + "include_subdomains": true + }, + { + "host": "hafniatimes.com", + "include_subdomains": true + }, + { + "host": "getdash.io", + "include_subdomains": true + }, + { + "host": "furkancaliskan.com", + "include_subdomains": true + }, + { + "host": "dynamicsnetwork.net", + "include_subdomains": true + }, + { + "host": "humblefinances.com", + "include_subdomains": true + }, + { + "host": "geblitzt.de", + "include_subdomains": true + }, + { + "host": "heh.ee", + "include_subdomains": true + }, + { + "host": "friendica.ch", + "include_subdomains": true + }, + { + "host": "freifunk-essen.de", + "include_subdomains": true + }, + { + "host": "imbrian.org", + "include_subdomains": true + }, + { + "host": "hoshinplan.com", + "include_subdomains": true + }, + { + "host": "heart.ge", + "include_subdomains": true + }, + { + "host": "grandlinecsk.ru", + "include_subdomains": true + }, + { + "host": "inbounder.io", + "include_subdomains": true + }, + { + "host": "ijsclubtilburg.nl", + "include_subdomains": true + }, + { + "host": "homa.website", + "include_subdomains": true + }, + { + "host": "internetbugbounty.org", + "include_subdomains": true + }, + { + "host": "inmyarea.com", + "include_subdomains": true + }, + { + "host": "iispeed.com", + "include_subdomains": true + }, + { + "host": "initq.net", + "include_subdomains": true + }, + { + "host": "immoverkauf24.de", + "include_subdomains": true + }, + { + "host": "immoverkauf24.at", + "include_subdomains": true + }, + { + "host": "glasgestaltung.biz", + "include_subdomains": true + }, + { + "host": "icq-project.net", + "include_subdomains": true + }, + { + "host": "jakenbake.com", + "include_subdomains": true + }, + { + "host": "jn1.me", + "include_subdomains": true + }, + { + "host": "jamesbywater.me.uk", + "include_subdomains": true + }, + { + "host": "johnguant.com", + "include_subdomains": true + }, + { + "host": "interviewpipeline.co.uk", + "include_subdomains": true + }, + { + "host": "gaptek.id", + "include_subdomains": true + }, + { + "host": "ipv6-handbuch.de", + "include_subdomains": true + }, + { + "host": "intim-uslugi-kazan.net", + "include_subdomains": true + }, + { + "host": "kingant.net", + "include_subdomains": true + }, + { + "host": "jeff393.com", + "include_subdomains": true + }, + { + "host": "jurriaan.ninja", + "include_subdomains": true + }, + { + "host": "jamiemagee.co.uk", + "include_subdomains": true + }, + { + "host": "kau-boys.com", + "include_subdomains": true + }, + { + "host": "junqtion.com", + "include_subdomains": true + }, + { + "host": "affinitysync.com", + "include_subdomains": true + }, + { + "host": "kickass.al", + "include_subdomains": true + }, + { + "host": "kantorosobisty.pl", + "include_subdomains": true + }, + { + "host": "kdm-online.de", + "include_subdomains": true + }, + { + "host": "linguatrip.com", + "include_subdomains": true + }, + { + "host": "korobi.io", + "include_subdomains": true + }, + { + "host": "gipsamsfashion.com", + "include_subdomains": true + }, + { + "host": "lachlankidson.net", + "include_subdomains": true + }, + { + "host": "kinderbasar-luhe.de", + "include_subdomains": true + }, + { + "host": "konsertoversikt.no", + "include_subdomains": true + }, + { + "host": "kbit.dk", + "include_subdomains": true + }, + { + "host": "locktheirphone.com", + "include_subdomains": true + }, + { + "host": "kschv-rdeck.de", + "include_subdomains": true + }, + { + "host": "kau-boys.de", + "include_subdomains": true + }, + { + "host": "kick-in.nl", + "include_subdomains": true + }, + { + "host": "kreativstrecke.de", + "include_subdomains": true + }, + { + "host": "manage.cm", + "include_subdomains": true + }, + { + "host": "mesvt.com", + "include_subdomains": true + }, + { + "host": "mhx.pw", + "include_subdomains": true + }, + { + "host": "liverewrite.com", + "include_subdomains": true + }, + { + "host": "leerliga.de", + "include_subdomains": true + }, + { + "host": "mc-venture.net", + "include_subdomains": true + }, + { + "host": "lukasztkacz.com", + "include_subdomains": true + }, + { + "host": "meta-db.com", + "include_subdomains": true + }, + { + "host": "mblankhorst.nl", + "include_subdomains": true + }, + { + "host": "muscleangels.com", + "include_subdomains": true + }, + { + "host": "modmountain.com", + "include_subdomains": true + }, + { + "host": "mark-semmler.de", + "include_subdomains": true + }, + { + "host": "new-black-order.com", + "include_subdomains": true + }, + { + "host": "mp3gratuiti.com", + "include_subdomains": true + }, + { + "host": "millistream.com", + "include_subdomains": true + }, + { + "host": "mega.nz", + "include_subdomains": true + }, + { + "host": "navycs.com", + "include_subdomains": true + }, + { + "host": "moula.com.au", + "include_subdomains": true + }, + { + "host": "mojapraca.sk", + "include_subdomains": true + }, + { + "host": "minkondom.nu", + "include_subdomains": true + }, + { + "host": "mercurystorm.co.za", + "include_subdomains": true + }, + { + "host": "musicwear.cz", + "include_subdomains": true + }, + { + "host": "nicky.io", + "include_subdomains": true + }, + { + "host": "mistacms.com", + "include_subdomains": true + }, + { + "host": "okonetwork.org.uk", + "include_subdomains": true + }, + { + "host": "noname-ev.de", + "include_subdomains": true + }, + { + "host": "nuos.org", + "include_subdomains": true + }, + { + "host": "onewpst.com", + "include_subdomains": true + }, + { + "host": "pirxpilot.me", + "include_subdomains": true + }, + { + "host": "organic-superfood.net", + "include_subdomains": true + }, + { + "host": "pirlitu.com", + "include_subdomains": true + }, + { + "host": "parsemail.org", + "include_subdomains": true + }, + { + "host": "ontimestamp.com", + "include_subdomains": true + }, + { + "host": "playkh.com", + "include_subdomains": true + }, + { + "host": "portalplatform.net", + "include_subdomains": true + }, + { + "host": "poed.com.au", + "include_subdomains": true + }, + { + "host": "petrachuk.ru", + "include_subdomains": true + }, + { + "host": "p8r.de", + "include_subdomains": true + }, + { + "host": "pcfeuerwehr.de", + "include_subdomains": true + }, + { + "host": "patterson.mp", + "include_subdomains": true + }, + { + "host": "poolvilla-margarita.net", + "include_subdomains": true + }, + { + "host": "pothe.de", + "include_subdomains": true + }, + { + "host": "robertglastra.com", + "include_subdomains": true + }, + { + "host": "progg.no", + "include_subdomains": true + }, + { + "host": "pothe.com", + "include_subdomains": true + }, + { + "host": "qixxit.de", + "include_subdomains": true + }, + { + "host": "robtex.net", + "include_subdomains": true + }, + { + "host": "qvitoo.com", + "include_subdomains": true + }, + { + "host": "richardwarrender.com", + "include_subdomains": true + }, + { + "host": "retroarms.com", + "include_subdomains": true + }, + { + "host": "rugirlfriend.com", + "include_subdomains": true + }, + { + "host": "rigolitch.fr", + "include_subdomains": true + }, + { + "host": "rxbusiness.com", + "include_subdomains": true + }, + { + "host": "retroarms.cz", + "include_subdomains": true + }, + { + "host": "scotthelme.com", + "include_subdomains": true + }, + { + "host": "ronvandordt.info", + "include_subdomains": true + }, + { + "host": "radtke.bayern", + "include_subdomains": true + }, + { + "host": "rambitteh.ru", + "include_subdomains": true + }, + { + "host": "securityheaders.io", + "include_subdomains": true + }, + { + "host": "seele.ca", + "include_subdomains": true + }, + { + "host": "schorel.ovh", + "include_subdomains": true + }, + { + "host": "schorelweb.nl", + "include_subdomains": true + }, + { + "host": "schoop.me", + "include_subdomains": true + }, + { + "host": "schlarp.com", + "include_subdomains": true + }, + { + "host": "socialspirit.com.br", + "include_subdomains": true + }, + { + "host": "rohlik.cz", + "include_subdomains": true + }, + { + "host": "shft.cl", + "include_subdomains": true + }, + { + "host": "socialrank.com", + "include_subdomains": true + }, + { + "host": "slicketl.com", + "include_subdomains": true + }, + { + "host": "searchbrothers.com", + "include_subdomains": true + }, + { + "host": "manfredimatteo.com", + "include_subdomains": true + }, + { + "host": "sneakynote.com", + "include_subdomains": true + }, + { + "host": "stemsims.com", + "include_subdomains": true + }, + { + "host": "liquorsanthe.in", + "include_subdomains": true + }, + { + "host": "seminariruum.ee", + "include_subdomains": true + }, + { + "host": "syncappate.com", + "include_subdomains": true + }, + { + "host": "sonafe.info", + "include_subdomains": true + }, + { + "host": "system.is", + "include_subdomains": true + }, + { + "host": "stolkschepen.nl", + "include_subdomains": true + }, + { + "host": "themarshallproject.org", + "include_subdomains": true + }, + { + "host": "scp-trens.notaires.fr", + "include_subdomains": true + }, + { + "host": "tbarter.com", + "include_subdomains": true + }, + { + "host": "syso.name", + "include_subdomains": true + }, + { + "host": "tonytan.io", + "include_subdomains": true + }, + { + "host": "uber.com", + "include_subdomains": true + }, + { + "host": "throwpass.com", + "include_subdomains": true + }, + { + "host": "travador.com", + "include_subdomains": true + }, + { + "host": "thom4s.info", + "include_subdomains": true + }, + { + "host": "thorgames.nl", + "include_subdomains": true + }, + { + "host": "tpbcdn.com", + "include_subdomains": true + }, + { + "host": "tppleague.me", + "include_subdomains": true + }, + { + "host": "techvalue.gr", + "include_subdomains": true + }, + { + "host": "vcsjones.com", + "include_subdomains": true + }, + { + "host": "vanhoutte.be", + "include_subdomains": true + }, + { + "host": "sneberger.cz", + "include_subdomains": true + }, + { + "host": "uniekglas.nl", + "include_subdomains": true + }, + { + "host": "varden.info", + "include_subdomains": true + }, + { + "host": "wikidata.org", + "include_subdomains": true + }, + { + "host": "vapemania.eu", + "include_subdomains": true + }, + { + "host": "vigo-krankenversicherung.de", + "include_subdomains": true + }, + { + "host": "xavierbarroso.com", + "include_subdomains": true + }, + { + "host": "wachter.biz", + "include_subdomains": true + }, + { + "host": "vbulletin-russia.com", + "include_subdomains": true + }, + { + "host": "vbulletinrussia.com", + "include_subdomains": true + }, + { + "host": "webstudio-n.com", + "include_subdomains": true + }, + { + "host": "wonderhost.info", + "include_subdomains": true + }, + { + "host": "winsec.nl", + "include_subdomains": true + }, + { + "host": "vbhelp.org", + "include_subdomains": true + }, + { + "host": "xgclan.com", + "include_subdomains": true + }, + { + "host": "yetcore.io", + "include_subdomains": true + }, + { + "host": "wpmeetup-berlin.de", + "include_subdomains": true + }, + { + "host": "xn--u9jv84l7ea468b.com", + "include_subdomains": true + }, + { + "host": "xn--knstler-n2a.tips", + "include_subdomains": true + }, + { + "host": "zcarrot.com", + "include_subdomains": true + }, + { + "host": "zcarot.com", + "include_subdomains": true + }, + { + "host": "zorntt.fr", + "include_subdomains": true + }, + { + "host": "ztan.tk", + "include_subdomains": true + }, + { + "host": "asm-x.com", + "include_subdomains": true + }, + { + "host": "ccblog.de", + "include_subdomains": true + }, + { + "host": "smiatek.name", + "include_subdomains": true + }, + { + "host": "korni22.org", + "include_subdomains": true + }, + { + "host": "student.andover.edu", + "include_subdomains": true + } + ] +} \ No newline at end of file From 29a34dbdb52cb005fd272a67ccb0bcf08363a25b Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sat, 18 Jul 2015 10:04:06 +1000 Subject: [PATCH 16/24] Resolves code review comments * Lots of rust-isms * Mutable iterator for modifying entries (much better) --- components/net/resource_task.rs | 63 +++++++++++------------------- python/servo/bootstrap_commands.py | 5 ++- tests/unit/net/resource_task.rs | 46 +++++++++++----------- 3 files changed, 48 insertions(+), 66 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 9ee9bb4699c..e4cb9de630e 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -163,17 +163,11 @@ pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result } fn preload_hsts_domains() -> Option { - match read_resource_file(&["hsts_preload.json"]) { - Ok(bytes) => { - match from_utf8(&bytes) { - Ok(hsts_preload_content) => { - HSTSList::new_from_preload(hsts_preload_content) - }, - Err(_) => None - } - }, - Err(_) => None - } + read_resource_file(&["hsts_preload.json"]).ok().and_then(|bytes| { + from_utf8(&bytes).ok().and_then(|hsts_preload_content| { + HSTSList::new_from_preload(hsts_preload_content) + }) + }) } /// Create a ResourceTask @@ -246,10 +240,7 @@ pub struct HSTSList { impl HSTSList { pub fn new_from_preload(preload_content: &str) -> Option { - match decode(preload_content) { - Ok(list) => Some(list), - Err(_) => None - } + decode(preload_content).ok() } pub fn is_host_secure(&self, host: &str) -> bool { @@ -286,33 +277,26 @@ impl HSTSList { if !have_domain && !have_subdomain { self.entries.push(entry); } else if !have_subdomain { - self.entries = self.entries.iter().fold(Vec::new(), |mut m, e| { + for e in &mut self.entries { if e.matches_domain(&entry.host) { - // Update the entry if there's an exact domain match. - m.push(entry.clone()); - } else { - // Ignore the new details if it's a subdomain match, or not - // a match at all. Just use the existing entry - m.push(e.clone()); + e.include_subdomains = entry.include_subdomains; + e.max_age = entry.max_age; } - - m - }); + } } } } pub fn secure_load_data(load_data: &LoadData) -> LoadData { - match &*load_data.url.scheme { - "http" => { - let mut secure_load_data = load_data.clone(); - let mut secure_url = load_data.url.clone(); - secure_url.scheme = "https".to_string(); - secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); + if &*load_data.url.scheme == "http" { + let mut secure_load_data = load_data.clone(); + let mut secure_url = load_data.url.clone(); + secure_url.scheme = "https".to_string(); + secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); - secure_load_data - }, - _ => load_data.clone() + secure_load_data + } else { + load_data.clone() } } @@ -367,10 +351,8 @@ impl ResourceChannelManager { consumer.send(self.resource_manager.cookie_storage.cookies_for_url(&url, source)).unwrap(); } ControlMsg::SetHSTSEntryForHost(host, include_subdomains, max_age) => { - match HSTSEntry::new(host, include_subdomains, max_age) { - Some(entry) => self.resource_manager.add_hsts_entry(entry), - /// Invalid entries (e.g. IP's don't matter) - None => () + if let Some(entry) = HSTSEntry::new(host, include_subdomains, max_age) { + self.resource_manager.add_hsts_entry(entry) } } ControlMsg::Exit => { @@ -428,9 +410,8 @@ impl ResourceManager { } pub fn add_hsts_entry(&mut self, entry: HSTSEntry) { - match self.hsts_list.as_mut() { - Some(list) => list.push(entry), - None => () + if let Some(list) = self.hsts_list.as_mut() { + list.push(entry) } } diff --git a/python/servo/bootstrap_commands.py b/python/servo/bootstrap_commands.py index 3eb501e2377..0e12b786342 100644 --- a/python/servo/bootstrap_commands.py +++ b/python/servo/bootstrap_commands.py @@ -218,10 +218,13 @@ class MachCommands(CommandBase): try: content_base64 = download_bytes("Chromium HSTS preload list", chromium_hsts_url) except urllib2.URLError, e: - print("Unable to download chromium HSTS preload list, are you connected to the internet?") + print("Unable to download chromium HSTS preload list; are you connected to the internet?") sys.exit(1) content_decoded = base64.b64decode(content_base64) + + # The chromium "json" has single line comments in it which, of course, + # are non-standard/non-valid json. Simply strip them out before parsing content_json = re.sub(r'//.*$', '', content_decoded, flags=re.MULTILINE) try: diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 9f72b4d54ed..55c9baf4107 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -2,10 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use net::resource_task::{ - new_resource_task, parse_hostsfile, replace_hosts, HSTSList, HSTSEntry, secure_load_data, - ResourceManager -}; +use net::resource_task::new_resource_task; +use net::resource_task::parse_hostsfile; +use net::resource_task::replace_hosts; +use net::resource_task::HSTSList; +use net::resource_task::HSTSEntry; +use net::resource_task::secure_load_data; +use net::resource_task::ResourceManager; use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::ProgressMsg; use std::borrow::ToOwned; @@ -83,10 +86,7 @@ fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false, None ); - match entry { - Some(_) => panic!("able to create HSTSEntry with IPv6 host"), - None => () - } + assert!(entry.is_none(), "able to create HSTSEntry with IPv6 host"); } #[test] @@ -95,10 +95,7 @@ fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { "4.4.4.4".to_string(), false, None ); - match entry { - Some(_) => panic!("able to create HSTSEntry with IPv6 host"), - None => () - } + assert!(entry.is_none(), "able to create HSTSEntry with IPv4 host"); } #[test] @@ -147,6 +144,10 @@ fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { assert!(list.entries.len() == 1) } +#[test] +fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() { +} + #[test] fn test_push_entry_to_hsts_list_should_add_an_entry() { let mut list = HSTSList { @@ -154,28 +155,25 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { }; assert!(!list.is_host_secure("mozilla.org")); + assert!(!list.is_host_secure("bugzilla.org")); list.push(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()); + list.push(HSTSEntry::new("bugzilla.org".to_string(), true, None).unwrap()); assert!(list.is_host_secure("mozilla.org")); + assert!(list.is_host_secure("bugzilla.org")); } #[test] fn test_parse_hsts_preload_should_return_none_when_json_invalid() { let mock_preload_content = "derp"; - match HSTSList::new_from_preload(mock_preload_content) { - Some(_) => assert!(false, "preload list should not have parsed"), - None => assert!(true) - } + assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") } #[test] fn test_parse_hsts_preload_should_return_none_when_json_contains_no_entries_key() { let mock_preload_content = "{\"nothing\": \"to see here\"}"; - match HSTSList::new_from_preload(mock_preload_content) { - Some(_) => assert!(false, "preload list should not have parsed"), - None => assert!(true) - } + assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") } #[test] @@ -189,8 +187,8 @@ fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { let hsts_list = HSTSList::new_from_preload(mock_preload_content); let entries = hsts_list.unwrap().entries; - assert!(entries.get(0).unwrap().host == "mozilla.org"); - assert!(entries.get(0).unwrap().include_subdomains == false); + assert!(entries[0].host == "mozilla.org"); + assert!(entries[0].include_subdomains == false); } #[test] @@ -274,7 +272,7 @@ fn test_secure_load_data_does_not_affect_non_http_schemas() { let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); let secure = secure_load_data(&load_data); - assert!(&secure.url.scheme == "file"); + assert_eq!(&secure.url.scheme, "file"); } #[test] @@ -282,7 +280,7 @@ fn test_secure_load_data_forces_an_http_host_in_list_to_https() { let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); let secure = secure_load_data(&load_data); - assert!(&secure.url.scheme == "https"); + assert_eq!(&secure.url.scheme, "https"); } #[test] From 02bd5cdc1b117f0260901fc39eb562b02ad719b6 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sat, 18 Jul 2015 10:39:22 +1000 Subject: [PATCH 17/24] Resolves remaining code review issues * Don't pass a boolean to the HSTSEntry constructor, use an enum instead * Don't clone when securing load data * Comment about the Url bug * Change remaining assert!(... == ...) to assert_eq!(..., ...) --- components/net/resource_task.rs | 44 +++++++++++++++++++-------- tests/unit/net/resource_task.rs | 53 +++++++++++++++++---------------- 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index e4cb9de630e..1448b32496c 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -200,14 +200,20 @@ pub struct HSTSEntry { pub timestamp: Option } +#[derive(PartialEq, Copy, Clone)] +pub enum Subdomains { + Included, + NotIncluded +} + impl HSTSEntry { - pub fn new(host: String, include_subdomains: bool, max_age: Option) -> Option { + pub fn new(host: String, subdomains: Subdomains, max_age: Option) -> Option { if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { None } else { Some(HSTSEntry { host: host, - include_subdomains: include_subdomains, + include_subdomains: (subdomains == Subdomains::Included), max_age: max_age, timestamp: Some(time::get_time().sec as u64) }) @@ -292,6 +298,10 @@ pub fn secure_load_data(load_data: &LoadData) -> LoadData { let mut secure_load_data = load_data.clone(); let mut secure_url = load_data.url.clone(); secure_url.scheme = "https".to_string(); + // The Url struct parses the port for a known scheme only once. + // Updating the scheme doesn't update the port internally, resulting in + // HTTPS connections attempted on port 80. Serialising and re-parsing + // the Url is a hack to get around this. secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); secure_load_data @@ -351,7 +361,13 @@ impl ResourceChannelManager { consumer.send(self.resource_manager.cookie_storage.cookies_for_url(&url, source)).unwrap(); } ControlMsg::SetHSTSEntryForHost(host, include_subdomains, max_age) => { - if let Some(entry) = HSTSEntry::new(host, include_subdomains, max_age) { + let subdomains = if include_subdomains { + Subdomains::Included + } else { + Subdomains::NotIncluded + }; + + if let Some(entry) = HSTSEntry::new(host, subdomains, max_age) { self.resource_manager.add_hsts_entry(entry) } } @@ -415,6 +431,15 @@ impl ResourceManager { } } + fn load_data_must_be_secured(&self, load_data: &LoadData) -> bool { + match (self.hsts_list.as_ref(), load_data.url.domain()) { + (Some(ref l), Some(ref h)) => { + l.is_host_secure(h) + }, + _ => false + } + } + fn load(&mut self, mut load_data: LoadData, consumer: LoadConsumer) { unsafe { if let Some(host_table) = HOST_TABLE { @@ -426,16 +451,9 @@ impl ResourceManager { load_data.preserved_headers.set(UserAgent(ua.clone())); }); - load_data = match (self.hsts_list.as_ref(), load_data.url.domain()) { - (Some(ref l), Some(ref h)) => { - if l.is_host_secure(h) { - secure_load_data(&load_data) - } else { - load_data.clone() - } - }, - _ => load_data.clone() - }; + if self.load_data_must_be_secured(&load_data) { + load_data = secure_load_data(&load_data) + } fn from_factory(factory: fn(LoadData, LoadConsumer, Arc)) -> Box) + Send> { diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index 55c9baf4107..e1c5eac78e3 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -7,6 +7,7 @@ use net::resource_task::parse_hostsfile; use net::resource_task::replace_hosts; use net::resource_task::HSTSList; use net::resource_task::HSTSEntry; +use net::resource_task::Subdomains; use net::resource_task::secure_load_data; use net::resource_task::ResourceManager; use net_traits::{ControlMsg, LoadData, LoadConsumer}; @@ -34,7 +35,7 @@ fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { let mut manager = ResourceManager::new(None, tx, Some(list), None); let entry = HSTSEntry::new( - "mozilla.org".to_string(), false, None + "mozilla.org".to_string(), Subdomains::NotIncluded, None ); assert!(!manager.is_host_sts("mozilla.org")); @@ -83,7 +84,7 @@ fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() { #[test] fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { let entry = HSTSEntry::new( - "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), false, None + "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), Subdomains::NotIncluded, None ); assert!(entry.is_none(), "able to create HSTSEntry with IPv6 host"); @@ -92,7 +93,7 @@ fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { #[test] fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { let entry = HSTSEntry::new( - "4.4.4.4".to_string(), false, None + "4.4.4.4".to_string(), Subdomains::NotIncluded, None ); assert!(entry.is_none(), "able to create HSTSEntry with IPv4 host"); @@ -101,10 +102,10 @@ fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { #[test] fn test_push_entry_with_0_max_age_evicts_entry_from_list() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, Some(500000u64)).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(500000u64)).unwrap()) }; - list.push(HSTSEntry::new("mozilla.org".to_string(), false, Some(0)).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(0)).unwrap()); assert!(list.is_host_secure("mozilla.org") == false) } @@ -112,10 +113,10 @@ fn test_push_entry_with_0_max_age_evicts_entry_from_list() { #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) }; - list.push(HSTSEntry::new("servo.mozilla.org".to_string(), false, None).unwrap()); + list.push(HSTSEntry::new("servo.mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); assert!(list.entries.len() == 1) } @@ -123,12 +124,12 @@ fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_a #[test] fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) }; assert!(list.is_host_secure("servo.mozilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); assert!(!list.is_host_secure("servo.mozilla.org")) } @@ -136,10 +137,10 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub #[test] fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()) }; - list.push(HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); assert!(list.entries.len() == 1) } @@ -157,8 +158,8 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { assert!(!list.is_host_secure("mozilla.org")); assert!(!list.is_host_secure("bugzilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()); - list.push(HSTSEntry::new("bugzilla.org".to_string(), true, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); + list.push(HSTSEntry::new("bugzilla.org".to_string(), Subdomains::Included, None).unwrap()); assert!(list.is_host_secure("mozilla.org")); assert!(list.is_host_secure("bugzilla.org")); @@ -187,8 +188,8 @@ fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { let hsts_list = HSTSList::new_from_preload(mock_preload_content); let entries = hsts_list.unwrap().entries; - assert!(entries[0].host == "mozilla.org"); - assert!(entries[0].include_subdomains == false); + assert_eq!(entries[0].host, "mozilla.org"); + assert!(!entries[0].include_subdomains); } #[test] @@ -197,52 +198,52 @@ fn test_hsts_list_with_no_entries_does_not_is_host_secure() { entries: Vec::new() }; - assert!(hsts_list.is_host_secure("mozilla.org") == false); + assert!(!hsts_list.is_host_secure("mozilla.org")); } #[test] fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] }; - assert!(hsts_list.is_host_secure("mozilla.org") == true); + assert!(hsts_list.is_host_secure("mozilla.org")); } #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] }; - assert!(hsts_list.is_host_secure("servo.mozilla.org") == true); + assert!(hsts_list.is_host_secure("servo.mozilla.org")); } #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), false, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] }; - assert!(hsts_list.is_host_secure("servo.mozilla.org") == false); + assert!(!hsts_list.is_host_secure("servo.mozilla.org")); } #[test] fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] }; - assert!(hsts_list.is_host_secure("servo-mozilla.org") == false); + assert!(!hsts_list.is_host_secure("servo-mozilla.org")); } #[test] fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), true, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] }; - assert!(hsts_list.is_host_secure("mozilla.org") == true); + assert!(hsts_list.is_host_secure("mozilla.org")); } #[test] From 826f56bdf3f73bc9105a252f909acd4de28fcc07 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sat, 18 Jul 2015 10:54:03 +1000 Subject: [PATCH 18/24] Moves HSTS code to it's own module --- components/net/hsts.rs | 145 +++++++++++++++++ components/net/lib.rs | 1 + components/net/resource_task.rs | 137 +--------------- tests/unit/net/hsts.rs | 273 ++++++++++++++++++++++++++++++++ tests/unit/net/lib.rs | 1 + tests/unit/net/resource_task.rs | 266 ------------------------------- 6 files changed, 426 insertions(+), 397 deletions(-) create mode 100644 components/net/hsts.rs create mode 100644 tests/unit/net/hsts.rs diff --git a/components/net/hsts.rs b/components/net/hsts.rs new file mode 100644 index 00000000000..8fcaa907b2c --- /dev/null +++ b/components/net/hsts.rs @@ -0,0 +1,145 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use regex::Regex; +use rustc_serialize::json::{decode}; +use time; +use url::Url; + +use std::str::{from_utf8}; + +use net_traits::LoadData; +use util::resource_files::read_resource_file; + +static IPV4_REGEX: Regex = regex!( + r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" +); +static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); + +#[derive(RustcDecodable, RustcEncodable, Clone)] +pub struct HSTSEntry { + pub host: String, + pub include_subdomains: bool, + pub max_age: Option, + pub timestamp: Option +} + +#[derive(PartialEq, Copy, Clone)] +pub enum Subdomains { + Included, + NotIncluded +} + +impl HSTSEntry { + pub fn new(host: String, subdomains: Subdomains, max_age: Option) -> Option { + if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { + None + } else { + Some(HSTSEntry { + host: host, + include_subdomains: (subdomains == Subdomains::Included), + max_age: max_age, + timestamp: Some(time::get_time().sec as u64) + }) + } + } + + pub fn is_expired(&self) -> bool { + match (self.max_age, self.timestamp) { + (Some(max_age), Some(timestamp)) => { + (time::get_time().sec as u64) - timestamp >= max_age + }, + + _ => false + } + } + + fn matches_domain(&self, host: &str) -> bool { + !self.is_expired() && self.host == host + } + + fn matches_subdomain(&self, host: &str) -> bool { + !self.is_expired() && host.ends_with(&format!(".{}", self.host)) + } +} + +#[derive(RustcDecodable, RustcEncodable)] +pub struct HSTSList { + pub entries: Vec +} + +impl HSTSList { + pub fn new_from_preload(preload_content: &str) -> Option { + decode(preload_content).ok() + } + + pub fn is_host_secure(&self, host: &str) -> bool { + // TODO - Should this be faster than O(n)? The HSTS list is only a few + // hundred or maybe thousand entries... + // + // Could optimise by searching for exact matches first (via a map or + // something), then checking for subdomains. + self.entries.iter().any(|e| { + if e.include_subdomains { + e.matches_subdomain(host) || e.matches_domain(host) + } else { + e.matches_domain(host) + } + }) + } + + fn has_domain(&self, host: &str) -> bool { + self.entries.iter().any(|e| { + e.matches_domain(&host) + }) + } + + fn has_subdomain(&self, host: &str) -> bool { + self.entries.iter().any(|e| { + e.matches_subdomain(host) + }) + } + + pub fn push(&mut self, entry: HSTSEntry) { + let have_domain = self.has_domain(&entry.host); + let have_subdomain = self.has_subdomain(&entry.host); + + if !have_domain && !have_subdomain { + self.entries.push(entry); + } else if !have_subdomain { + for e in &mut self.entries { + if e.matches_domain(&entry.host) { + e.include_subdomains = entry.include_subdomains; + e.max_age = entry.max_age; + } + } + } + } +} + +pub fn preload_hsts_domains() -> Option { + read_resource_file(&["hsts_preload.json"]).ok().and_then(|bytes| { + from_utf8(&bytes).ok().and_then(|hsts_preload_content| { + HSTSList::new_from_preload(hsts_preload_content) + }) + }) +} + +pub fn secure_load_data(load_data: &LoadData) -> LoadData { + if &*load_data.url.scheme == "http" { + let mut secure_load_data = load_data.clone(); + let mut secure_url = load_data.url.clone(); + secure_url.scheme = "https".to_string(); + // The Url struct parses the port for a known scheme only once. + // Updating the scheme doesn't update the port internally, resulting in + // HTTPS connections attempted on port 80. Serialising and re-parsing + // the Url is a hack to get around this. + secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); + + secure_load_data + } else { + load_data.clone() + } +} + diff --git a/components/net/lib.rs b/components/net/lib.rs index 45af99e1a70..34f7cfff4ce 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -40,6 +40,7 @@ pub mod image_cache_task; pub mod net_error_list; pub mod pub_domains; pub mod resource_task; +pub mod hsts; pub mod storage_task; pub mod mime_classifier; diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 1448b32496c..0554a263f62 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -17,15 +17,18 @@ use net_traits::{Metadata, ProgressMsg, ResourceTask, AsyncResponseTarget, Respo use net_traits::ProgressMsg::Done; use util::opts; use util::task::spawn_named; -use util::resource_files::read_resource_file; use url::Url; +use hsts::HSTSList; +use hsts::HSTSEntry; +use hsts::Subdomains; +use hsts::preload_hsts_domains; +use hsts::secure_load_data; + use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; use hyper::mime::{Mime, TopLevel, SubLevel}; -use rustc_serialize::json::{decode}; - use regex::Regex; use std::borrow::ToOwned; use std::boxed::FnBox; @@ -33,10 +36,8 @@ use std::collections::HashMap; use std::env; use std::fs::File; use std::io::{BufReader, Read}; -use std::str::{from_utf8}; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; -use time; static mut HOST_TABLE: Option<*mut HashMap> = None; static IPV4_REGEX: Regex = regex!( @@ -162,14 +163,6 @@ pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result } } -fn preload_hsts_domains() -> Option { - read_resource_file(&["hsts_preload.json"]).ok().and_then(|bytes| { - from_utf8(&bytes).ok().and_then(|hsts_preload_content| { - HSTSList::new_from_preload(hsts_preload_content) - }) - }) -} - /// Create a ResourceTask pub fn new_resource_task(user_agent: Option, devtools_chan: Option>) -> ResourceTask { @@ -192,124 +185,6 @@ pub fn new_resource_task(user_agent: Option, setup_chan } -#[derive(RustcDecodable, RustcEncodable, Clone)] -pub struct HSTSEntry { - pub host: String, - pub include_subdomains: bool, - pub max_age: Option, - pub timestamp: Option -} - -#[derive(PartialEq, Copy, Clone)] -pub enum Subdomains { - Included, - NotIncluded -} - -impl HSTSEntry { - pub fn new(host: String, subdomains: Subdomains, max_age: Option) -> Option { - if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { - None - } else { - Some(HSTSEntry { - host: host, - include_subdomains: (subdomains == Subdomains::Included), - max_age: max_age, - timestamp: Some(time::get_time().sec as u64) - }) - } - } - - pub fn is_expired(&self) -> bool { - match (self.max_age, self.timestamp) { - (Some(max_age), Some(timestamp)) => { - (time::get_time().sec as u64) - timestamp >= max_age - }, - - _ => false - } - } - - fn matches_domain(&self, host: &str) -> bool { - !self.is_expired() && self.host == host - } - - fn matches_subdomain(&self, host: &str) -> bool { - !self.is_expired() && host.ends_with(&format!(".{}", self.host)) - } -} - -#[derive(RustcDecodable, RustcEncodable)] -pub struct HSTSList { - pub entries: Vec -} - -impl HSTSList { - pub fn new_from_preload(preload_content: &str) -> Option { - decode(preload_content).ok() - } - - pub fn is_host_secure(&self, host: &str) -> bool { - // TODO - Should this be faster than O(n)? The HSTS list is only a few - // hundred or maybe thousand entries... - // - // Could optimise by searching for exact matches first (via a map or - // something), then checking for subdomains. - self.entries.iter().any(|e| { - if e.include_subdomains { - e.matches_subdomain(host) || e.matches_domain(host) - } else { - e.matches_domain(host) - } - }) - } - - fn has_domain(&self, host: &str) -> bool { - self.entries.iter().any(|e| { - e.matches_domain(&host) - }) - } - - fn has_subdomain(&self, host: &str) -> bool { - self.entries.iter().any(|e| { - e.matches_subdomain(host) - }) - } - - pub fn push(&mut self, entry: HSTSEntry) { - let have_domain = self.has_domain(&entry.host); - let have_subdomain = self.has_subdomain(&entry.host); - - if !have_domain && !have_subdomain { - self.entries.push(entry); - } else if !have_subdomain { - for e in &mut self.entries { - if e.matches_domain(&entry.host) { - e.include_subdomains = entry.include_subdomains; - e.max_age = entry.max_age; - } - } - } - } -} - -pub fn secure_load_data(load_data: &LoadData) -> LoadData { - if &*load_data.url.scheme == "http" { - let mut secure_load_data = load_data.clone(); - let mut secure_url = load_data.url.clone(); - secure_url.scheme = "https".to_string(); - // The Url struct parses the port for a known scheme only once. - // Updating the scheme doesn't update the port internally, resulting in - // HTTPS connections attempted on port 80. Serialising and re-parsing - // the Url is a hack to get around this. - secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); - - secure_load_data - } else { - load_data.clone() - } -} - pub fn parse_hostsfile(hostsfile_content: &str) -> Box> { let mut host_table = HashMap::new(); let lines: Vec<&str> = hostsfile_content.split('\n').collect(); diff --git a/tests/unit/net/hsts.rs b/tests/unit/net/hsts.rs new file mode 100644 index 00000000000..7a93d7dd564 --- /dev/null +++ b/tests/unit/net/hsts.rs @@ -0,0 +1,273 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use net::hsts::HSTSList; +use net::hsts::HSTSEntry; +use net::hsts::Subdomains; +use net::hsts::secure_load_data; +use net::resource_task::ResourceManager; +use net_traits::LoadData; +use std::sync::mpsc::channel; +use url::Url; +use time; + +#[test] +fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { + let list = HSTSList { + entries: Vec::new() + }; + + let (tx, _) = channel(); + let mut manager = ResourceManager::new(None, tx, Some(list), None); + + let entry = HSTSEntry::new( + "mozilla.org".to_string(), Subdomains::NotIncluded, None + ); + + assert!(!manager.is_host_sts("mozilla.org")); + + manager.add_hsts_entry(entry.unwrap()); + + assert!(manager.is_host_sts("mozilla.org")) +} + +#[test] +fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(20), + timestamp: None + }; + + assert!(!entry.is_expired()); +} + +#[test] +fn test_hsts_entry_is_not_expired_when_it_has_no_max_age() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: None, + timestamp: Some(time::get_time().sec as u64) + }; + + assert!(!entry.is_expired()); +} + +#[test] +fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() { + let entry = HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(10), + timestamp: Some(time::get_time().sec as u64 - 20u64) + }; + + assert!(entry.is_expired()); +} + +#[test] +fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { + let entry = HSTSEntry::new( + "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), Subdomains::NotIncluded, None + ); + + assert!(entry.is_none(), "able to create HSTSEntry with IPv6 host"); +} + +#[test] +fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { + let entry = HSTSEntry::new( + "4.4.4.4".to_string(), Subdomains::NotIncluded, None + ); + + assert!(entry.is_none(), "able to create HSTSEntry with IPv4 host"); +} + +#[test] +fn test_push_entry_with_0_max_age_evicts_entry_from_list() { + let mut list = HSTSList { + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(500000u64)).unwrap()) + }; + + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(0)).unwrap()); + + assert!(list.is_host_secure("mozilla.org") == false) +} + +#[test] +fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { + let mut list = HSTSList { + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) + }; + + list.push(HSTSEntry::new("servo.mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + + assert!(list.entries.len() == 1) +} + +#[test] +fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { + let mut list = HSTSList { + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) + }; + + assert!(list.is_host_secure("servo.mozilla.org")); + + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + + assert!(!list.is_host_secure("servo.mozilla.org")) +} + +#[test] +fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { + let mut list = HSTSList { + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()) + }; + + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + + assert!(list.entries.len() == 1) +} + +#[test] +fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() { +} + +#[test] +fn test_push_entry_to_hsts_list_should_add_an_entry() { + let mut list = HSTSList { + entries: Vec::new() + }; + + assert!(!list.is_host_secure("mozilla.org")); + assert!(!list.is_host_secure("bugzilla.org")); + + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); + list.push(HSTSEntry::new("bugzilla.org".to_string(), Subdomains::Included, None).unwrap()); + + assert!(list.is_host_secure("mozilla.org")); + assert!(list.is_host_secure("bugzilla.org")); +} + +#[test] +fn test_parse_hsts_preload_should_return_none_when_json_invalid() { + let mock_preload_content = "derp"; + assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") +} + +#[test] +fn test_parse_hsts_preload_should_return_none_when_json_contains_no_entries_key() { + let mock_preload_content = "{\"nothing\": \"to see here\"}"; + assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") +} + +#[test] +fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { + let mock_preload_content = "{\ + \"entries\": [\ + {\"host\": \"mozilla.org\",\ + \"include_subdomains\": false}\ + ]\ + }"; + let hsts_list = HSTSList::new_from_preload(mock_preload_content); + let entries = hsts_list.unwrap().entries; + + assert_eq!(entries[0].host, "mozilla.org"); + assert!(!entries[0].include_subdomains); +} + +#[test] +fn test_hsts_list_with_no_entries_does_not_is_host_secure() { + let hsts_list = HSTSList { + entries: Vec::new() + }; + + assert!(!hsts_list.is_host_secure("mozilla.org")); +} + +#[test] +fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] + }; + + assert!(hsts_list.is_host_secure("mozilla.org")); +} + +#[test] +fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + }; + + assert!(hsts_list.is_host_secure("servo.mozilla.org")); +} + +#[test] +fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] + }; + + assert!(!hsts_list.is_host_secure("servo.mozilla.org")); +} + +#[test] +fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + }; + + assert!(!hsts_list.is_host_secure("servo-mozilla.org")); +} + +#[test] +fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + }; + + assert!(hsts_list.is_host_secure("mozilla.org")); +} + +#[test] +fn test_hsts_list_with_expired_entry_is_not_is_host_secure() { + let hsts_list = HSTSList { + entries: vec![HSTSEntry { + host: "mozilla.org".to_string(), + include_subdomains: false, + max_age: Some(20), + timestamp: Some(time::get_time().sec as u64 - 100u64) + }] + }; + + assert!(!hsts_list.is_host_secure("mozilla.org")); +} + +#[test] +fn test_secure_load_data_does_not_change_explicit_port() { + let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); + let secure = secure_load_data(&load_data); + + assert!(secure.url.port().unwrap() == 8080u16); +} + +#[test] +fn test_secure_load_data_does_not_affect_non_http_schemas() { + let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); + let secure = secure_load_data(&load_data); + + assert_eq!(&secure.url.scheme, "file"); +} + +#[test] +fn test_secure_load_data_forces_an_http_host_in_list_to_https() { + let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); + let secure = secure_load_data(&load_data); + + assert_eq!(&secure.url.scheme, "https"); +} + diff --git a/tests/unit/net/lib.rs b/tests/unit/net/lib.rs index 335cbd721a6..d9d0f05a79f 100644 --- a/tests/unit/net/lib.rs +++ b/tests/unit/net/lib.rs @@ -14,3 +14,4 @@ extern crate time; #[cfg(test)] mod data_loader; #[cfg(test)] mod mime_classifier; #[cfg(test)] mod resource_task; +#[cfg(test)] mod hsts; diff --git a/tests/unit/net/resource_task.rs b/tests/unit/net/resource_task.rs index e1c5eac78e3..989558c2f21 100644 --- a/tests/unit/net/resource_task.rs +++ b/tests/unit/net/resource_task.rs @@ -5,19 +5,12 @@ use net::resource_task::new_resource_task; use net::resource_task::parse_hostsfile; use net::resource_task::replace_hosts; -use net::resource_task::HSTSList; -use net::resource_task::HSTSEntry; -use net::resource_task::Subdomains; -use net::resource_task::secure_load_data; -use net::resource_task::ResourceManager; use net_traits::{ControlMsg, LoadData, LoadConsumer}; use net_traits::ProgressMsg; use std::borrow::ToOwned; use std::collections::HashMap; use std::sync::mpsc::channel; use url::Url; -use time; - #[test] fn test_exit() { @@ -25,265 +18,6 @@ fn test_exit() { resource_task.send(ControlMsg::Exit).unwrap(); } -#[test] -fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { - let list = HSTSList { - entries: Vec::new() - }; - - let (tx, _) = channel(); - let mut manager = ResourceManager::new(None, tx, Some(list), None); - - let entry = HSTSEntry::new( - "mozilla.org".to_string(), Subdomains::NotIncluded, None - ); - - assert!(!manager.is_host_sts("mozilla.org")); - - manager.add_hsts_entry(entry.unwrap()); - - assert!(manager.is_host_sts("mozilla.org")) -} - -#[test] -fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() { - let entry = HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: false, - max_age: Some(20), - timestamp: None - }; - - assert!(!entry.is_expired()); -} - -#[test] -fn test_hsts_entry_is_not_expired_when_it_has_no_max_age() { - let entry = HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: false, - max_age: None, - timestamp: Some(time::get_time().sec as u64) - }; - - assert!(!entry.is_expired()); -} - -#[test] -fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() { - let entry = HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: false, - max_age: Some(10), - timestamp: Some(time::get_time().sec as u64 - 20u64) - }; - - assert!(entry.is_expired()); -} - -#[test] -fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { - let entry = HSTSEntry::new( - "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), Subdomains::NotIncluded, None - ); - - assert!(entry.is_none(), "able to create HSTSEntry with IPv6 host"); -} - -#[test] -fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { - let entry = HSTSEntry::new( - "4.4.4.4".to_string(), Subdomains::NotIncluded, None - ); - - assert!(entry.is_none(), "able to create HSTSEntry with IPv4 host"); -} - -#[test] -fn test_push_entry_with_0_max_age_evicts_entry_from_list() { - let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(500000u64)).unwrap()) - }; - - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(0)).unwrap()); - - assert!(list.is_host_secure("mozilla.org") == false) -} - -#[test] -fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { - let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) - }; - - list.push(HSTSEntry::new("servo.mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); - - assert!(list.entries.len() == 1) -} - -#[test] -fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { - let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) - }; - - assert!(list.is_host_secure("servo.mozilla.org")); - - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); - - assert!(!list.is_host_secure("servo.mozilla.org")) -} - -#[test] -fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { - let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()) - }; - - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); - - assert!(list.entries.len() == 1) -} - -#[test] -fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() { -} - -#[test] -fn test_push_entry_to_hsts_list_should_add_an_entry() { - let mut list = HSTSList { - entries: Vec::new() - }; - - assert!(!list.is_host_secure("mozilla.org")); - assert!(!list.is_host_secure("bugzilla.org")); - - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); - list.push(HSTSEntry::new("bugzilla.org".to_string(), Subdomains::Included, None).unwrap()); - - assert!(list.is_host_secure("mozilla.org")); - assert!(list.is_host_secure("bugzilla.org")); -} - -#[test] -fn test_parse_hsts_preload_should_return_none_when_json_invalid() { - let mock_preload_content = "derp"; - assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") -} - -#[test] -fn test_parse_hsts_preload_should_return_none_when_json_contains_no_entries_key() { - let mock_preload_content = "{\"nothing\": \"to see here\"}"; - assert!(HSTSList::new_from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed") -} - -#[test] -fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() { - let mock_preload_content = "{\ - \"entries\": [\ - {\"host\": \"mozilla.org\",\ - \"include_subdomains\": false}\ - ]\ - }"; - let hsts_list = HSTSList::new_from_preload(mock_preload_content); - let entries = hsts_list.unwrap().entries; - - assert_eq!(entries[0].host, "mozilla.org"); - assert!(!entries[0].include_subdomains); -} - -#[test] -fn test_hsts_list_with_no_entries_does_not_is_host_secure() { - let hsts_list = HSTSList { - entries: Vec::new() - }; - - assert!(!hsts_list.is_host_secure("mozilla.org")); -} - -#[test] -fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] - }; - - assert!(hsts_list.is_host_secure("mozilla.org")); -} - -#[test] -fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] - }; - - assert!(hsts_list.is_host_secure("servo.mozilla.org")); -} - -#[test] -fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] - }; - - assert!(!hsts_list.is_host_secure("servo.mozilla.org")); -} - -#[test] -fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] - }; - - assert!(!hsts_list.is_host_secure("servo-mozilla.org")); -} - -#[test] -fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] - }; - - assert!(hsts_list.is_host_secure("mozilla.org")); -} - -#[test] -fn test_hsts_list_with_expired_entry_is_not_is_host_secure() { - let hsts_list = HSTSList { - entries: vec![HSTSEntry { - host: "mozilla.org".to_string(), - include_subdomains: false, - max_age: Some(20), - timestamp: Some(time::get_time().sec as u64 - 100u64) - }] - }; - - assert!(!hsts_list.is_host_secure("mozilla.org")); -} - -#[test] -fn test_secure_load_data_does_not_change_explicit_port() { - let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); - let secure = secure_load_data(&load_data); - - assert!(secure.url.port().unwrap() == 8080u16); -} - -#[test] -fn test_secure_load_data_does_not_affect_non_http_schemas() { - let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); - let secure = secure_load_data(&load_data); - - assert_eq!(&secure.url.scheme, "file"); -} - -#[test] -fn test_secure_load_data_forces_an_http_host_in_list_to_https() { - let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); - let secure = secure_load_data(&load_data); - - assert_eq!(&secure.url.scheme, "https"); -} - #[test] fn test_bad_scheme() { let resource_task = new_resource_task(None, None); From f2148f06b1f67d18be471288824fd3a30348efcb Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sat, 18 Jul 2015 17:23:46 +1000 Subject: [PATCH 19/24] Moves the HSTS replacement code to http_loader This respects STS for redirects as well. --- components/net/hsts.rs | 20 ++++++-------------- components/net/http_loader.rs | 29 +++++++++++++++++++++++++---- components/net/resource_task.rs | 24 +++++------------------- tests/unit/net/hsts.rs | 26 +++++++++++++------------- 4 files changed, 49 insertions(+), 50 deletions(-) diff --git a/components/net/hsts.rs b/components/net/hsts.rs index 8fcaa907b2c..74756a63afa 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -9,7 +9,6 @@ use url::Url; use std::str::{from_utf8}; -use net_traits::LoadData; use util::resource_files::read_resource_file; static IPV4_REGEX: Regex = regex!( @@ -64,7 +63,7 @@ impl HSTSEntry { } } -#[derive(RustcDecodable, RustcEncodable)] +#[derive(RustcDecodable, RustcEncodable, Clone)] pub struct HSTSList { pub entries: Vec } @@ -126,20 +125,13 @@ pub fn preload_hsts_domains() -> Option { }) } -pub fn secure_load_data(load_data: &LoadData) -> LoadData { - if &*load_data.url.scheme == "http" { - let mut secure_load_data = load_data.clone(); - let mut secure_url = load_data.url.clone(); +pub fn secure_url(url: &Url) -> Url { + if &*url.scheme == "http" { + let mut secure_url = url.clone(); secure_url.scheme = "https".to_string(); - // The Url struct parses the port for a known scheme only once. - // Updating the scheme doesn't update the port internally, resulting in - // HTTPS connections attempted on port 80. Serialising and re-parsing - // the Url is a hack to get around this. - secure_load_data.url = Url::parse(&secure_url.serialize()).unwrap(); - - secure_load_data + Url::parse(&secure_url.serialize()).unwrap() } else { - load_data.clone() + url.clone() } } diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 9b422ea07d3..9ade3469746 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -7,6 +7,7 @@ use net_traits::ProgressMsg::{Payload, Done}; use devtools_traits::{DevtoolsControlMsg, NetworkEvent}; use mime_classifier::MIMEClassifier; use resource_task::{start_sending_opt, start_sending_sniffed_opt}; +use hsts::{HSTSList, secure_url}; use log; use std::collections::HashSet; @@ -33,11 +34,13 @@ use uuid; use std::borrow::ToOwned; use std::boxed::FnBox; -pub fn factory(cookies_chan: Sender, devtools_chan: Option>) +pub fn factory(cookies_chan: Sender, + devtools_chan: Option>, + hsts_list: Option) -> Box) + Send> { box move |load_data, senders, classifier| { spawn_named("http_loader".to_owned(), - move || load(load_data, senders, classifier, cookies_chan, devtools_chan)) + move || load(load_data, senders, classifier, cookies_chan, devtools_chan, hsts_list)) } } @@ -69,8 +72,21 @@ fn read_block(reader: &mut R) -> Result { } } -fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc, - cookies_chan: Sender, devtools_chan: Option>) { +fn request_must_be_secured(hsts_list: Option<&HSTSList>, url: &Url) -> bool { + match (hsts_list.as_ref(), url.domain()) { + (Some(ref l), Some(ref h)) => { + l.is_host_secure(h) + }, + _ => false + } +} + +fn load(mut load_data: LoadData, + start_chan: LoadConsumer, + classifier: Arc, + cookies_chan: Sender, + devtools_chan: Option>, + hsts_list: Option) { // FIXME: At the time of writing this FIXME, servo didn't have any central // location for configuration. If you're reading this and such a // repository DOES exist, please update this constant to use it. @@ -101,6 +117,11 @@ fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc max_redirects { send_error(url, "too many redirects".to_string(), start_chan); return; diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 0554a263f62..8ddaf11db83 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -23,7 +23,6 @@ use hsts::HSTSList; use hsts::HSTSEntry; use hsts::Subdomains; use hsts::preload_hsts_domains; -use hsts::secure_load_data; use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; @@ -293,25 +292,16 @@ impl ResourceManager { } } - pub fn is_host_sts(&self, host: &str) -> bool { - match self.hsts_list.as_ref() { - Some(list) => list.is_host_secure(host), - None => false - } - } - pub fn add_hsts_entry(&mut self, entry: HSTSEntry) { if let Some(list) = self.hsts_list.as_mut() { list.push(entry) } } - fn load_data_must_be_secured(&self, load_data: &LoadData) -> bool { - match (self.hsts_list.as_ref(), load_data.url.domain()) { - (Some(ref l), Some(ref h)) => { - l.is_host_secure(h) - }, - _ => false + pub fn is_host_sts(&self, host: &str) -> bool { + match self.hsts_list.as_ref() { + Some(list) => list.is_host_secure(host), + None => false } } @@ -326,10 +316,6 @@ impl ResourceManager { load_data.preserved_headers.set(UserAgent(ua.clone())); }); - if self.load_data_must_be_secured(&load_data) { - load_data = secure_load_data(&load_data) - } - fn from_factory(factory: fn(LoadData, LoadConsumer, Arc)) -> Box) + Send> { box move |load_data, senders, classifier| { @@ -340,7 +326,7 @@ impl ResourceManager { let loader = match &*load_data.url.scheme { "file" => from_factory(file_loader::factory), "http" | "https" | "view-source" => - http_loader::factory(self.resource_task.clone(), self.devtools_chan.clone()), + http_loader::factory(self.resource_task.clone(), self.devtools_chan.clone(), self.hsts_list.clone()), "data" => from_factory(data_loader::factory), "about" => from_factory(about_loader::factory), _ => { diff --git a/tests/unit/net/hsts.rs b/tests/unit/net/hsts.rs index 7a93d7dd564..31b5182d83e 100644 --- a/tests/unit/net/hsts.rs +++ b/tests/unit/net/hsts.rs @@ -5,7 +5,7 @@ use net::hsts::HSTSList; use net::hsts::HSTSEntry; use net::hsts::Subdomains; -use net::hsts::secure_load_data; +use net::hsts::secure_url; use net::resource_task::ResourceManager; use net_traits::LoadData; use std::sync::mpsc::channel; @@ -248,26 +248,26 @@ fn test_hsts_list_with_expired_entry_is_not_is_host_secure() { } #[test] -fn test_secure_load_data_does_not_change_explicit_port() { - let load_data = LoadData::new(Url::parse("http://mozilla.org:8080/").unwrap(), None); - let secure = secure_load_data(&load_data); +fn test_secure_url_does_not_change_explicit_port() { + let url = Url::parse("http://mozilla.org:8080/").unwrap(); + let secure = secure_url(&url); - assert!(secure.url.port().unwrap() == 8080u16); + assert!(secure.port().unwrap() == 8080u16); } #[test] -fn test_secure_load_data_does_not_affect_non_http_schemas() { - let load_data = LoadData::new(Url::parse("file://mozilla.org").unwrap(), None); - let secure = secure_load_data(&load_data); +fn test_secure_url_does_not_affect_non_http_schemas() { + let url = Url::parse("file://mozilla.org").unwrap(); + let secure = secure_url(&url); - assert_eq!(&secure.url.scheme, "file"); + assert_eq!(&secure.scheme, "file"); } #[test] -fn test_secure_load_data_forces_an_http_host_in_list_to_https() { - let load_data = LoadData::new(Url::parse("http://mozilla.org").unwrap(), None); - let secure = secure_load_data(&load_data); +fn test_secure_url_forces_an_http_host_in_list_to_https() { + let url = Url::parse("http://mozilla.org").unwrap(); + let secure = secure_url(&url); - assert_eq!(&secure.url.scheme, "https"); + assert_eq!(&secure.scheme, "https"); } From 11f5be6d854634f5bbc8c4bb9d5a0d2fdd15cbb3 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sun, 19 Jul 2015 09:54:20 +1000 Subject: [PATCH 20/24] Responds to more code review feedback * Use regex from resource task * Don't have an option of an HSTS list, default to empty --- components/net/hsts.rs | 13 +++++++------ components/net/http_loader.rs | 14 +++++++------- components/net/resource_task.rs | 27 +++++++++++---------------- tests/unit/net/hsts.rs | 20 ++++++++++++++------ 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/components/net/hsts.rs b/components/net/hsts.rs index 74756a63afa..f7c7e995a17 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -2,20 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use regex::Regex; use rustc_serialize::json::{decode}; use time; use url::Url; +use resource_task::{IPV4_REGEX, IPV6_REGEX}; use std::str::{from_utf8}; use util::resource_files::read_resource_file; -static IPV4_REGEX: Regex = regex!( - r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" -); -static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); - #[derive(RustcDecodable, RustcEncodable, Clone)] pub struct HSTSEntry { pub host: String, @@ -69,6 +64,12 @@ pub struct HSTSList { } impl HSTSList { + pub fn new() -> HSTSList { + HSTSList { + entries: vec![] + } + } + pub fn new_from_preload(preload_content: &str) -> Option { decode(preload_content).ok() } diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 9ade3469746..cac53a0b608 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -36,7 +36,7 @@ use std::boxed::FnBox; pub fn factory(cookies_chan: Sender, devtools_chan: Option>, - hsts_list: Option) + hsts_list: HSTSList) -> Box) + Send> { box move |load_data, senders, classifier| { spawn_named("http_loader".to_owned(), @@ -72,10 +72,10 @@ fn read_block(reader: &mut R) -> Result { } } -fn request_must_be_secured(hsts_list: Option<&HSTSList>, url: &Url) -> bool { - match (hsts_list.as_ref(), url.domain()) { - (Some(ref l), Some(ref h)) => { - l.is_host_secure(h) +fn request_must_be_secured(hsts_list: &HSTSList, url: &Url) -> bool { + match url.domain() { + Some(ref h) => { + hsts_list.is_host_secure(h) }, _ => false } @@ -86,7 +86,7 @@ fn load(mut load_data: LoadData, classifier: Arc, cookies_chan: Sender, devtools_chan: Option>, - hsts_list: Option) { + hsts_list: HSTSList) { // FIXME: At the time of writing this FIXME, servo didn't have any central // location for configuration. If you're reading this and such a // repository DOES exist, please update this constant to use it. @@ -117,7 +117,7 @@ fn load(mut load_data: LoadData, loop { iters = iters + 1; - if request_must_be_secured(hsts_list.as_ref(), &url) { + if request_must_be_secured(&hsts_list, &url) { info!("{} is in the strict transport security list, requesting secure host", url); url = secure_url(&url); } diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 8ddaf11db83..8d5f23343b7 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -19,10 +19,7 @@ use util::opts; use util::task::spawn_named; use url::Url; -use hsts::HSTSList; -use hsts::HSTSEntry; -use hsts::Subdomains; -use hsts::preload_hsts_domains; +use hsts::{HSTSList, HSTSEntry, Subdomains, preload_hsts_domains}; use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; @@ -39,10 +36,10 @@ use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; static mut HOST_TABLE: Option<*mut HashMap> = None; -static IPV4_REGEX: Regex = regex!( +pub static IPV4_REGEX: Regex = regex!( r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" ); -static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); +pub static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$"); pub fn global_init() { //TODO: handle bad file path @@ -165,7 +162,10 @@ pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result /// Create a ResourceTask pub fn new_resource_task(user_agent: Option, devtools_chan: Option>) -> ResourceTask { - let hsts_preload = preload_hsts_domains(); + let hsts_preload = match preload_hsts_domains() { + Some(list) => list, + None => HSTSList::new() + }; let (setup_chan, setup_port) = channel(); let setup_chan_clone = setup_chan.clone(); @@ -260,13 +260,13 @@ pub struct ResourceManager { resource_task: Sender, mime_classifier: Arc, devtools_chan: Option>, - hsts_list: Option + hsts_list: HSTSList } impl ResourceManager { pub fn new(user_agent: Option, resource_task: Sender, - hsts_list: Option, + hsts_list: HSTSList, devtools_channel: Option>) -> ResourceManager { ResourceManager { user_agent: user_agent, @@ -293,16 +293,11 @@ impl ResourceManager { } pub fn add_hsts_entry(&mut self, entry: HSTSEntry) { - if let Some(list) = self.hsts_list.as_mut() { - list.push(entry) - } + self.hsts_list.push(entry); } pub fn is_host_sts(&self, host: &str) -> bool { - match self.hsts_list.as_ref() { - Some(list) => list.is_host_secure(host), - None => false - } + self.hsts_list.is_host_secure(host) } fn load(&mut self, mut load_data: LoadData, consumer: LoadConsumer) { diff --git a/tests/unit/net/hsts.rs b/tests/unit/net/hsts.rs index 31b5182d83e..bdefa6b4645 100644 --- a/tests/unit/net/hsts.rs +++ b/tests/unit/net/hsts.rs @@ -7,7 +7,6 @@ use net::hsts::HSTSEntry; use net::hsts::Subdomains; use net::hsts::secure_url; use net::resource_task::ResourceManager; -use net_traits::LoadData; use std::sync::mpsc::channel; use url::Url; use time; @@ -19,7 +18,7 @@ fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { }; let (tx, _) = channel(); - let mut manager = ResourceManager::new(None, tx, Some(list), None); + let mut manager = ResourceManager::new(None, tx, list, None); let entry = HSTSEntry::new( "mozilla.org".to_string(), Subdomains::NotIncluded, None @@ -134,10 +133,6 @@ fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { #[test] fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() { -} - -#[test] -fn test_push_entry_to_hsts_list_should_add_an_entry() { let mut list = HSTSList { entries: Vec::new() }; @@ -152,6 +147,19 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { assert!(list.is_host_secure("bugzilla.org")); } +#[test] +fn test_push_entry_to_hsts_list_should_add_an_entry() { + let mut list = HSTSList { + entries: Vec::new() + }; + + assert!(!list.is_host_secure("mozilla.org")); + + list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); + + assert!(list.is_host_secure("mozilla.org")); +} + #[test] fn test_parse_hsts_preload_should_return_none_when_json_invalid() { let mock_preload_content = "derp"; From 82cafc42744f772f9bae35e7768e0425cd001a14 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sun, 19 Jul 2015 13:32:24 +1000 Subject: [PATCH 21/24] Passes an Arc> to threads instead of cloning --- components/net/http_loader.rs | 7 ++++--- components/net/resource_task.rs | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index cac53a0b608..4c417bcad3a 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -24,6 +24,7 @@ use std::error::Error; use openssl::ssl::{SslContext, SslMethod, SSL_VERIFY_PEER}; use std::io::{self, Read, Write}; use std::sync::Arc; +use std::sync::Mutex; use std::sync::mpsc::{Sender, channel}; use util::task::spawn_named; use util::resource_files::resources_dir_path; @@ -36,7 +37,7 @@ use std::boxed::FnBox; pub fn factory(cookies_chan: Sender, devtools_chan: Option>, - hsts_list: HSTSList) + hsts_list: Arc>) -> Box) + Send> { box move |load_data, senders, classifier| { spawn_named("http_loader".to_owned(), @@ -86,7 +87,7 @@ fn load(mut load_data: LoadData, classifier: Arc, cookies_chan: Sender, devtools_chan: Option>, - hsts_list: HSTSList) { + hsts_list: Arc>) { // FIXME: At the time of writing this FIXME, servo didn't have any central // location for configuration. If you're reading this and such a // repository DOES exist, please update this constant to use it. @@ -117,7 +118,7 @@ fn load(mut load_data: LoadData, loop { iters = iters + 1; - if request_must_be_secured(&hsts_list, &url) { + if request_must_be_secured(&hsts_list.lock().unwrap(), &url) { info!("{} is in the strict transport security list, requesting secure host", url); url = secure_url(&url); } diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index 8d5f23343b7..f221b77e51d 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -33,6 +33,7 @@ use std::env; use std::fs::File; use std::io::{BufReader, Read}; use std::sync::Arc; +use std::sync::Mutex; use std::sync::mpsc::{channel, Receiver, Sender}; static mut HOST_TABLE: Option<*mut HashMap> = None; @@ -260,7 +261,7 @@ pub struct ResourceManager { resource_task: Sender, mime_classifier: Arc, devtools_chan: Option>, - hsts_list: HSTSList + hsts_list: Arc> } impl ResourceManager { @@ -274,7 +275,7 @@ impl ResourceManager { resource_task: resource_task, mime_classifier: Arc::new(MIMEClassifier::new()), devtools_chan: devtools_channel, - hsts_list: hsts_list + hsts_list: Arc::new(Mutex::new(hsts_list)) } } } @@ -293,11 +294,11 @@ impl ResourceManager { } pub fn add_hsts_entry(&mut self, entry: HSTSEntry) { - self.hsts_list.push(entry); + self.hsts_list.lock().unwrap().push(entry); } pub fn is_host_sts(&self, host: &str) -> bool { - self.hsts_list.is_host_secure(host) + self.hsts_list.lock().unwrap().is_host_secure(host) } fn load(&mut self, mut load_data: LoadData, consumer: LoadConsumer) { From bae979137ad54c4c4b50dfce7771401285456053 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sun, 19 Jul 2015 13:56:37 +1000 Subject: [PATCH 22/24] Moves HSTS includeSubdomains enum to net_traits --- components/net/hsts.rs | 11 ++----- components/net/resource_task.rs | 10 ++---- components/net_traits/lib.rs | 8 ++++- components/servo/Cargo.lock | 2 +- tests/unit/net/hsts.rs | 56 +++++++++++++++++++++------------ 5 files changed, 49 insertions(+), 38 deletions(-) diff --git a/components/net/hsts.rs b/components/net/hsts.rs index f7c7e995a17..2945ce0dbe5 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -5,6 +5,7 @@ use rustc_serialize::json::{decode}; use time; use url::Url; +use net_traits::IncludeSubdomains; use resource_task::{IPV4_REGEX, IPV6_REGEX}; use std::str::{from_utf8}; @@ -19,20 +20,14 @@ pub struct HSTSEntry { pub timestamp: Option } -#[derive(PartialEq, Copy, Clone)] -pub enum Subdomains { - Included, - NotIncluded -} - impl HSTSEntry { - pub fn new(host: String, subdomains: Subdomains, max_age: Option) -> Option { + pub fn new(host: String, subdomains: IncludeSubdomains, max_age: Option) -> Option { if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) { None } else { Some(HSTSEntry { host: host, - include_subdomains: (subdomains == Subdomains::Included), + include_subdomains: (subdomains == IncludeSubdomains::Included), max_age: max_age, timestamp: Some(time::get_time().sec as u64) }) diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index f221b77e51d..1e857102e33 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -19,7 +19,7 @@ use util::opts; use util::task::spawn_named; use url::Url; -use hsts::{HSTSList, HSTSEntry, Subdomains, preload_hsts_domains}; +use hsts::{HSTSList, HSTSEntry, preload_hsts_domains}; use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; @@ -236,13 +236,7 @@ impl ResourceChannelManager { consumer.send(self.resource_manager.cookie_storage.cookies_for_url(&url, source)).unwrap(); } ControlMsg::SetHSTSEntryForHost(host, include_subdomains, max_age) => { - let subdomains = if include_subdomains { - Subdomains::Included - } else { - Subdomains::NotIncluded - }; - - if let Some(entry) = HSTSEntry::new(host, subdomains, max_age) { + if let Some(entry) = HSTSEntry::new(host, include_subdomains, max_age) { self.resource_manager.add_hsts_entry(entry) } } diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 5da6357d333..0ceb00939f8 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -119,6 +119,12 @@ pub enum LoadConsumer { /// Handle to a resource task pub type ResourceTask = Sender; +#[derive(PartialEq, Copy, Clone)] +pub enum IncludeSubdomains { + Included, + NotIncluded +} + pub enum ControlMsg { /// Request the data associated with a particular URL Load(LoadData, LoadConsumer), @@ -127,7 +133,7 @@ pub enum ControlMsg { /// Retrieve the stored cookies for a given URL GetCookiesForUrl(Url, Sender>, CookieSource), /// Store a domain's STS information - SetHSTSEntryForHost(String, bool, Option), + SetHSTSEntryForHost(String, IncludeSubdomains, Option), Exit } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 3c87137b941..b1d022693f0 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -875,8 +875,8 @@ dependencies = [ "hyper 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "net 0.0.1", "net_traits 0.0.1", - "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] diff --git a/tests/unit/net/hsts.rs b/tests/unit/net/hsts.rs index bdefa6b4645..23d455c5aae 100644 --- a/tests/unit/net/hsts.rs +++ b/tests/unit/net/hsts.rs @@ -4,7 +4,7 @@ use net::hsts::HSTSList; use net::hsts::HSTSEntry; -use net::hsts::Subdomains; +use net_traits::IncludeSubdomains; use net::hsts::secure_url; use net::resource_task::ResourceManager; use std::sync::mpsc::channel; @@ -21,7 +21,7 @@ fn test_add_hsts_entry_to_resource_manager_adds_an_hsts_entry() { let mut manager = ResourceManager::new(None, tx, list, None); let entry = HSTSEntry::new( - "mozilla.org".to_string(), Subdomains::NotIncluded, None + "mozilla.org".to_string(), IncludeSubdomains::NotIncluded, None ); assert!(!manager.is_host_sts("mozilla.org")); @@ -70,7 +70,7 @@ fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() { #[test] fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { let entry = HSTSEntry::new( - "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), Subdomains::NotIncluded, None + "2001:0db8:0000:0000:0000:ff00:0042:8329".to_string(), IncludeSubdomains::NotIncluded, None ); assert!(entry.is_none(), "able to create HSTSEntry with IPv6 host"); @@ -79,7 +79,7 @@ fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() { #[test] fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { let entry = HSTSEntry::new( - "4.4.4.4".to_string(), Subdomains::NotIncluded, None + "4.4.4.4".to_string(), IncludeSubdomains::NotIncluded, None ); assert!(entry.is_none(), "able to create HSTSEntry with IPv4 host"); @@ -88,10 +88,12 @@ fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() { #[test] fn test_push_entry_with_0_max_age_evicts_entry_from_list() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(500000u64)).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, Some(500000u64)).unwrap()) }; - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, Some(0)).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, Some(0)).unwrap()); assert!(list.is_host_secure("mozilla.org") == false) } @@ -99,10 +101,12 @@ fn test_push_entry_with_0_max_age_evicts_entry_from_list() { #[test] fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()) }; - list.push(HSTSEntry::new("servo.mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + list.push(HSTSEntry::new("servo.mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()); assert!(list.entries.len() == 1) } @@ -110,12 +114,14 @@ fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_a #[test] fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()) }; assert!(list.is_host_secure("servo.mozilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()); assert!(!list.is_host_secure("servo.mozilla.org")) } @@ -123,10 +129,12 @@ fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_sub #[test] fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() { let mut list = HSTSList { - entries: vec!(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()) + entries: vec!(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()) }; - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()); assert!(list.entries.len() == 1) } @@ -140,8 +148,10 @@ fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() { assert!(!list.is_host_secure("mozilla.org")); assert!(!list.is_host_secure("bugzilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); - list.push(HSTSEntry::new("bugzilla.org".to_string(), Subdomains::Included, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()); + list.push(HSTSEntry::new("bugzilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()); assert!(list.is_host_secure("mozilla.org")); assert!(list.is_host_secure("bugzilla.org")); @@ -155,7 +165,8 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { assert!(!list.is_host_secure("mozilla.org")); - list.push(HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()); + list.push(HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()); assert!(list.is_host_secure("mozilla.org")); } @@ -199,7 +210,8 @@ fn test_hsts_list_with_no_entries_does_not_is_host_secure() { #[test] fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()] }; assert!(hsts_list.is_host_secure("mozilla.org")); @@ -208,7 +220,8 @@ fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() { #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()] }; assert!(hsts_list.is_host_secure("servo.mozilla.org")); @@ -217,7 +230,8 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secu #[test] fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::NotIncluded, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::NotIncluded, None).unwrap()] }; assert!(!hsts_list.is_host_secure("servo.mozilla.org")); @@ -226,7 +240,8 @@ fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host #[test] fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()] }; assert!(!hsts_list.is_host_secure("servo-mozilla.org")); @@ -235,7 +250,8 @@ fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_sec #[test] fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() { let hsts_list = HSTSList { - entries: vec![HSTSEntry::new("mozilla.org".to_string(), Subdomains::Included, None).unwrap()] + entries: vec![HSTSEntry::new("mozilla.org".to_string(), + IncludeSubdomains::Included, None).unwrap()] }; assert!(hsts_list.is_host_secure("mozilla.org")); From 5014da42fc726b68b62d7864806ec12fd06c5d5f Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sun, 19 Jul 2015 14:34:01 +1000 Subject: [PATCH 23/24] Only secure URL's that aren't already to HTTPS. Cuts down on logger spam, and unnecessary Url::clone's --- components/net/http_loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 4c417bcad3a..bfb4dbfb94a 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -118,7 +118,7 @@ fn load(mut load_data: LoadData, loop { iters = iters + 1; - if request_must_be_secured(&hsts_list.lock().unwrap(), &url) { + if &*url.scheme != "https" && request_must_be_secured(&hsts_list.lock().unwrap(), &url) { info!("{} is in the strict transport security list, requesting secure host", url); url = secure_url(&url); } From 118122da382622f4c7e8e16174a37e9870f004d9 Mon Sep 17 00:00:00 2001 From: Sam Gibson Date: Sun, 19 Jul 2015 23:36:27 +1200 Subject: [PATCH 24/24] Uses the approach suggested by @SimonSapin for changing Url scheme servo/rust-url#61 --- components/net/hsts.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/net/hsts.rs b/components/net/hsts.rs index 2945ce0dbe5..db9dcb4b9d3 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -125,7 +125,11 @@ pub fn secure_url(url: &Url) -> Url { if &*url.scheme == "http" { let mut secure_url = url.clone(); secure_url.scheme = "https".to_string(); - Url::parse(&secure_url.serialize()).unwrap() + secure_url.relative_scheme_data_mut() + .map(|scheme_data| { + scheme_data.default_port = Some(443); + }); + secure_url } else { url.clone() }