tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2015
- 20 participants
- 856 discussions
commit 4ed9de8fe5760a60e04298d86bc05780ea7378eb
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:07:34 2015 -0300
Minor changes to drive script
---
upload/bundles2drive.py | 108 ++++++++++++++++++++++++++++-------------------
1 file changed, 65 insertions(+), 43 deletions(-)
diff --git a/upload/bundles2drive.py b/upload/bundles2drive.py
index 8c329bf..9612382 100644
--- a/upload/bundles2drive.py
+++ b/upload/bundles2drive.py
@@ -16,10 +16,11 @@ import re
import os
import gnupg
import hashlib
+import logging
import ConfigParser
import gettor.core
-#import google drive libs
+# import google drive libs
import httplib2
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
@@ -51,7 +52,7 @@ def valid_format(file, osys):
file)
elif(osys == 'osx'):
m = re.search(
- 'TorBrowser-\d\.\d\.\d-osx\d\d_(\w\w)(-\w\w)?\.dmg',
+ 'TorBrowser-\d\.\d\.\d-osx\d\d_(\w\w)(-\w\w)?\.dmg',
file)
if m:
return True
@@ -143,21 +144,21 @@ def upload_files(client, basedir):
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'linux'):
+ and valid_format(name, 'linux'):
files.append(name)
p = re.compile('.*\.exe$')
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'windows'):
+ and valid_format(name, 'windows'):
files.append(name)
p = re.compile('.*\.dmg$')
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'osx'):
+ and valid_format(name, 'osx'):
files.append(name)
# dictionary to store file names and IDs
@@ -173,33 +174,44 @@ def upload_files(client, basedir):
continue
# upload tor browser installer
- file_body = MediaFileUpload(abs_file, resumable=True)
+ file_body = MediaFileUpload(
+ abs_file,
+ mimetype="application/octet-stream",
+ resumable=True
+ )
body = {
- 'title': file
+ 'title': file
}
print "Uploading '%s'..." % file
try:
- file_data = drive_service.files().insert(body=body, media_body=file_body).execute()
+ file_data = drive_service.files().insert(
+ body=body,
+ media_body=file_body
+ ).execute()
except errors.HttpError, e:
print str(e)
# upload signature
asc_body = MediaFileUpload(abs_asc, resumable=True)
asc_head = {
- 'title': "%s.asc" % file
+ 'title': "%s.asc" % file
}
print "Uploading '%s'..." % asc
try:
- asc_data = drive_service.files().insert(body=asc_head, media_body=asc_body).execute()
+ asc_data = drive_service.files().insert(
+ body=asc_head,
+ media_body=asc_body
+ ).execute()
except errors.HttpError, e:
print str(e)
# add filenames and file id to dict
files_dict[file] = file_data['id']
- files_dict[asc] = asc_data['id']
+ files_dict[asc] = asc_data['id']
return files_dict
+
def share_file(service, file_id):
"""Make files public
@@ -207,26 +219,28 @@ def share_file(service, file_id):
link to file.
:param: file_id (string)
-
+
:return: (string) url to shared file
-
+
"""
permission = {
- 'type': "anyone",
- 'role': "reader",
- 'withLink': True
+ 'type': "anyone",
+ 'role': "reader",
+ 'withLink': True
}
-
+
try:
service.permissions().insert(
- fileId=file_id, body=permission).execute()
+ fileId=file_id,
+ body=permission
+ ).execute()
except errors.HttpError, error:
- print('An error occured while sharing: %s' % file_id)
+ print('An error occured while sharing: %s' % file_id)
try:
file = service.files().get(fileId=file_id).execute()
except errors.HttpError, error:
- print('Error occured while fetch public link for file: %s' % file_id)
+ print('Error occured while fetch public link for file: %s' % file_id)
print("Uploaded to %s" % file['webContentLink'])
return file['webContentLink']
@@ -250,29 +264,33 @@ if __name__ == '__main__':
print "Authenticating..."
- flow = OAuth2WebServerFlow(client_id, app_secret, OAUTH_SCOPE,
- redirect_uri=REDIRECT_URI)
+ flow = OAuth2WebServerFlow(
+ client_id,
+ app_secret,
+ OAUTH_SCOPE,
+ redirect_uri=REDIRECT_URI
+ )
# If no valid token found, need to prompt user.
# this should only occur once
if not refresh_token:
- flow.params['access_type'] = 'offline'
- flow.params['approval_prompt'] = 'force'
- authorize_url = flow.step1_get_authorize_url()
- print 'Go to the following link in your browser: ' + authorize_url
- code = raw_input('Enter verification code: ').strip()
- try:
- credentials = flow.step2_exchange(code)
- except FlowExchangeError as e:
- print str(e)
-
- # oauth2 credentials instance must be stored as json string
- config.set('app', 'refresh_token', credentials.to_json())
- with open('drive.cfg', 'wb') as configfile:
+ flow.params['access_type'] = 'offline'
+ flow.params['approval_prompt'] = 'force'
+ authorize_url = flow.step1_get_authorize_url()
+ print 'Go to the following link in your browser: ' + authorize_url
+ code = raw_input('Enter verification code: ').strip()
+ try:
+ credentials = flow.step2_exchange(code)
+ except FlowExchangeError as e:
+ print str(e)
+
+ # oauth2 credentials instance must be stored as json string
+ config.set('app', 'refresh_token', credentials.to_json())
+ with open('drive.cfg', 'wb') as configfile:
config.write(configfile)
else:
- # we already have a valid token
- credentials = Credentials.new_from_json(refresh_token)
+ # we already have a valid token
+ credentials = Credentials.new_from_json(refresh_token)
# authenticate with oauth2
http = httplib2.Http()
@@ -281,7 +299,6 @@ if __name__ == '__main__':
# initialize drive instance
drive_service = build('drive', 'v2', http=http)
-
# import key fingerprint
gpg = gnupg.GPG()
key_data = open(tbb_key).read()
@@ -309,7 +326,7 @@ if __name__ == '__main__':
for file in uploaded_files.keys():
# only run for tor browser installers
if p4.match(file):
- continue
+ continue
asc = "%s.asc" % file
abs_file = os.path.abspath(os.path.join(upload_dir, file))
abs_asc = os.path.abspath(os.path.join(upload_dir, asc))
@@ -317,10 +334,15 @@ if __name__ == '__main__':
sha_file = get_file_sha256(abs_file)
# build links
- link_file = share_file(drive_service,
- uploaded_files[file])
- link_asc = share_file(drive_service,
- uploaded_files["%s.asc" % file])
+ link_file = share_file(
+ drive_service,
+ uploaded_files[file]
+ )
+
+ link_asc = share_file(
+ drive_service,
+ uploaded_files["%s.asc" % file]
+ )
if p1.match(file):
osys, arch, lc = get_bundle_info(file, 'linux')
1
0

[gettor/master] Added direct link to downloads section in http(s) mirrors
by ilv@torproject.org 03 Nov '15
by ilv@torproject.org 03 Nov '15
03 Nov '15
commit 87758bd0ec34a52a995d0e5973ca81ebf61203d6
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:13:44 2015 -0300
Added direct link to downloads section in http(s) mirrors
---
get_mirrors.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/get_mirrors.py b/get_mirrors.py
index 9c4b0c4..afa4cc9 100644
--- a/get_mirrors.py
+++ b/get_mirrors.py
@@ -158,6 +158,15 @@ def is_json(my_json):
return True
+def add_tpo_link(url):
+ """Add the download link for Tor Browser."""
+ uri = 'projects/torbrowser.html.en#downloads'
+ if url.endswith('/'):
+ return "%s%s" % (url, uri)
+ else:
+ return "%s/%s" % (url, uri)
+
+
def add_entry(mirrors, columns, elements):
"""Add entry to mirrors list."""
entry = {}
@@ -172,9 +181,15 @@ def add_entry(mirrors, columns, elements):
def add_mirror(file, entry, proto):
"""Add mirror to mirrors list."""
+ # if proto requested is http(s), we add link to download section
+ if PROTOS[proto] == 'http' or PROTOS[proto] == 'https':
+ uri = add_tpo_link(entry[proto])
+ else:
+ uri = entry[proto]
+
file.write(
"%s - by %s (%s)\n" % (
- entry[proto],
+ uri,
entry['orgName'],
entry['subRegion'],
)
1
0
commit e81d9c681ba7998038a1ae626a00949766b498c7
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:05:53 2015 -0300
Send mirrors option
---
get_mirrors.py | 338 ++++++
gettor/smtp.py | 239 ++--
lang/smtp/i18n/en/LC_MESSAGES/en.po | 19 +
mirrors-list.txt | 58 +
smtp.cfg | 3 +-
tor-mirrors | 2187 +++++++++++++++++++++++++++++++++++
tor-mirrors.csv | 116 ++
7 files changed, 2867 insertions(+), 93 deletions(-)
diff --git a/get_mirrors.py b/get_mirrors.py
new file mode 100644
index 0000000..9c4b0c4
--- /dev/null
+++ b/get_mirrors.py
@@ -0,0 +1,338 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of GetTor
+#
+# :authors: Israel Leiva <ilv(a)torproject.org>
+# see also AUTHORS file
+#
+# :license: This is Free Software. See LICENSE for license information.
+
+"""get_mirrors -- Download the list of tpo's mirrors for GetTor."""
+
+import os
+import json
+import codecs
+import logging
+import argparse
+
+
+from OpenSSL import SSL
+from OpenSSL import crypto
+
+from twisted.web import client
+from twisted.python import log
+from twisted.internet import ssl
+from twisted.internet import defer
+from twisted.internet import protocol
+from twisted.internet import reactor
+from twisted.internet.error import TimeoutError
+from twisted.internet.error import DNSLookupError
+from twisted.internet.error import ConnectionRefusedError
+
+from gettor import utils
+
+# Associate each protocol with its column name in tor-mirrors.csv
+PROTOS = {
+ 'https': 'httpsWebsiteMirror',
+ 'http': 'httpWebsiteMirror',
+ 'rsync': 'rsyncWebsiteMirror',
+ 'https-dist': 'httpsDistMirror',
+ 'http-dist': 'httpDistMirror',
+ 'rsync-dist': 'rsyncDistMirror',
+ 'ftp': 'ftpWebsiteMirror',
+ 'onion': 'hiddenServiceMirror',
+}
+
+# Tor Project's website certificate
+# $ openssl s_client -showcerts -connect tpo:443 < /dev/null > tpo.pem
+CERT_TPO = '/path/to/gettor/tpo.pem'
+
+
+# Taken from get-tor-exits (BridgeDB)
+class FileWriter(protocol.Protocol):
+ """Read a downloaded file incrementally and write to file."""
+ def __init__(self, finished, file):
+ """Create a FileWriter.
+
+ .. warning:: We currently only handle the first 2MB of a file. Files
+ over 2MB will be truncated prematurely. *note*: this should be
+ enough for the mirrors file.
+
+ :param finished: A :class:`~twisted.internet.defer.Deferred` which
+ will fire when another portion of the download is complete.
+ """
+ self.finished = finished
+ self.remaining = 1024 * 1024 * 2
+ self.fh = file
+
+ def dataReceived(self, bytes):
+ """Write a portion of the download with ``bytes`` size to disk."""
+ if self.remaining:
+ display = bytes[:self.remaining]
+ self.fh.write(display)
+ self.fh.flush()
+ self.remaining -= len(display)
+
+ def connectionLost(self, reason):
+ """Called when the download is complete."""
+ logging.info('Finished receiving mirrors list: %s'
+ % reason.getErrorMessage())
+ self.finished.callback(None)
+
+
+# Based in tor2web.utils.ssl (Tor2web)
+class HTTPSVerifyingContextFactory(ssl.ClientContextFactory):
+ def __init__(self, cn):
+ self.cn = cn
+ #
+ # From https://docs.python.org/2/library/ssl.html#ssl-security
+ #
+ # "SSL versions 2 and 3 are considered insecure and are therefore
+ # dangerous to use. If you want maximum compatibility between clients
+ # and servers, it is recommended to use PROTOCOL_SSLv23 as the protocol
+ # version and then disable SSLv2 and SSLv3 explicitly"
+ #
+ self.method = SSL.SSLv23_METHOD
+
+ def getContext(self, hostname, port):
+ """Get this connection's OpenSSL context.
+
+ We disable SSLv2 and SSLv3. We also check the certificate received
+ is the one we expect (using the "common name").
+
+ """
+ ctx = self._contextFactory(self.method)
+ ctx.set_options(SSL.OP_NO_SSLv2)
+ ctx.set_options(SSL.OP_NO_SSLv3)
+ ctx.set_verify(
+ SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
+ self.verifyCN
+ )
+
+ return ctx
+
+ def verifyCN(self, connection, x509, errno, depth, preverifyOK):
+ # DEBUG: print "%s == %s ?" % (self.cn, x509.get_subject().commonName)
+
+ # Somehow, if I don't set this to true, the verifyCN doesn't go
+ # down in the chain, I don't know if this is OK
+ verify = True
+ if depth == 0:
+ if self.cn == x509.get_subject().commonName:
+ verify = True
+ else:
+ verify = False
+ return verify
+
+
+# Based in get-tor-exits (BridgeDB)
+def handle(failure):
+ """Handle a **failure**."""
+ if failure.type == ConnectionRefusedError:
+ logging.error("Couldn't download file; connection was refused.")
+ elif failure.type == DNSLookupError:
+ logging.error("Couldn't download file; domain resolution failed.")
+ elif failure.type == TimeoutError:
+ logging.error("Couldn't download file; connection timed out.")
+ else:
+ logging.error("Couldn't download file.")
+
+ print "Couldn't download file. Check the log."
+ os._exit(-1)
+
+
+# Taken from get-tor-exits (BridgeDB)
+def writeToFile(response, filename):
+ """Write requested content to filename."""
+ finished = defer.Deferred()
+ response.deliverBody(FileWriter(finished, filename))
+ return finished
+
+
+def is_json(my_json):
+ """Check if json generated is valid."""
+ try:
+ json_object = json.loads(my_json)
+ except ValueError, e:
+ return False
+ return True
+
+
+def add_entry(mirrors, columns, elements):
+ """Add entry to mirrors list."""
+ entry = {}
+ count = 0
+ for e in elements:
+ e = e.replace("\n", '')
+ entry[columns[count]] = e
+ count = count + 1
+
+ mirrors.append(entry)
+
+
+def add_mirror(file, entry, proto):
+ """Add mirror to mirrors list."""
+ file.write(
+ "%s - by %s (%s)\n" % (
+ entry[proto],
+ entry['orgName'],
+ entry['subRegion'],
+ )
+ )
+
+
+def main():
+ """Script to get the list of tpo's mirrors from tpo and adapt it to
+ be used by GetTor.
+
+ Usage: python2.7 get_mirrors.py [-h] [--proto protocol]
+
+ By default, the protocol is 'https'. Possible values of protcol are:
+
+ http, https, rsync, ftp, onion, http-dist, https-dist, rsync-dist.
+
+ """
+ parser = argparse.ArgumentParser(
+ description="Utility to download tpo's mirrors and make it usable\
+ by GetTor."
+ )
+
+ parser.add_argument(
+ '-p', '--proto',
+ default='https',
+ help='Protocol filter. Possible values: http, https, rsync, ftp, onion\
+ http-dist, https-dist, rsync-dist. Default to https.')
+
+ args = parser.parse_args()
+ p = args.proto
+
+ gettor_path = '/path/to/gettor/'
+ csv_path = os.path.join(gettor_path, 'tor-mirrors.csv')
+ json_path = os.path.join(gettor_path, 'tor-mirrors')
+ mirrors_list = os.path.join(gettor_path, 'mirrors-list.txt')
+
+ # Load tpo certificate and extract common name, we'll later compare this
+ # with the certificate sent by tpo to check we're really taltking to it
+ try:
+ data = open(CERT_TPO).read()
+ x509 = crypto.load_certificate(crypto.FILETYPE_PEM, data)
+ cn_tpo = x509.get_subject().commonName
+ except Exception as e:
+ logging.error("Error with certificate: %s" % str(e))
+ return
+
+ # While we wait the json of mirrors to be implemented in tpo, we need
+ # to download the csv file and transform it to json
+
+ # The code below is based in get-tor-exits script from BridgeDB and
+ # the tor2web.utils.ssl module from Tor2web
+ url = 'https://www.torproject.org/include/tor-mirrors.csv'
+
+ try:
+ fh = open(csv_path, 'w')
+ except IOError as e:
+ logging.error("Could not open %s" % csv_path)
+ return
+
+ logging.info("Requesting %s..." % url)
+
+ # If certificate don't match an exception will be raised
+ # this is my first experience with twisted, maybe I'll learn to handle
+ # this better some time in the future...
+ contextFactory = HTTPSVerifyingContextFactory(cn_tpo)
+ agent = client.Agent(reactor, contextFactory)
+ d = agent.request("GET", url)
+ d.addCallback(writeToFile, fh)
+ d.addErrback(handle)
+ d.addCallbacks(log.msg, log.err)
+
+ if not reactor.running:
+ d.addCallback(lambda ignored: reactor.stop())
+ reactor.run()
+
+ logging.info("File downloaded!")
+
+ # Now transform it to json -- I couldn't find out how to use a
+ # two-character delimiter with the csv package, so I decided to handle
+ # the csv data by hand. We are doing this until #16601 gets deployed.
+ # https://trac.torproject.org/projects/tor/ticket/16601
+
+ # Code below is based in update-mirrors-json.py script from tpo
+
+ # These are the names of each column e.g. adminContact
+ columns = []
+ # List of mirrors to be built
+ mirrors = []
+
+ logging.info("Transforming csv data into json...")
+ logging.info("Getting data from csv")
+ try:
+ with codecs.open(csv_path, "rb", "utf-8") as csvfile:
+ for line in csvfile:
+ elements = line.split(", ")
+ # first entry have the names of the columns
+ if not columns:
+ columns = elements
+ else:
+ add_entry(mirrors, columns, elements)
+ except IOError as e:
+ logging.error("Couldn't read csv file: %s" % str(e))
+ return
+
+ logging.info("Creating json")
+ if is_json(json.dumps(mirrors)):
+ try:
+ with codecs.open(json_path, "w", "utf-8") as jsonfile:
+ # Make pretty json
+ json.dump(
+ mirrors,
+ jsonfile,
+ sort_keys=True,
+ indent=4,
+ separators=(',', ': '),
+ encoding="utf-8",
+ )
+ except IOError as e:
+ logging.error("Couldn't write json: %s" % str(e))
+ return
+ else:
+ logging.error("Invalid json file")
+ return
+
+ # Now make the mirrors list to be used by GetTor
+ logging.info("Reading json")
+ try:
+ mirrors_json = codecs.open(json_path, "rb", "utf-8")
+ mirrors = json.load(mirrors_json)
+ except IOError as e:
+ logging.error("Couldn't open %s" % json_path)
+ return
+
+ logging.info("Creating new list with protocol: %s" % p)
+ try:
+ list = codecs.open(mirrors_list, "w", "utf-8")
+ for entry in mirrors:
+ if args.proto is not 'all':
+ for e in entry:
+ if e == PROTOS[p] and entry[PROTOS[p]]:
+ add_mirror(list, entry, PROTOS[p])
+ else:
+ for k, v in PROTOS:
+ if entry[v]:
+ add_mirror(list, entry, v)
+ logging.info("List created: %s" % mirrors_list)
+ except IOError as e:
+ logging.error("Couldn't open %s" % mirrors_list)
+ return
+
+if __name__ == "__main__":
+ logging_format = utils.get_logging_format()
+ logging.basicConfig(
+ filename='/path/to/gettor/log/get-mirrors.log',
+ format=logging_format,
+ datefmt="%Y-%m-%d %H:%M:%S",
+ level=logging.INFO
+ )
+ logging.info("Started")
+ main()
+ logging.info("Finished")
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 655b5df..4db3ac7 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -22,7 +22,10 @@ import smtplib
import datetime
import ConfigParser
+from email import Encoders
+from email.MIMEBase import MIMEBase
from email.mime.text import MIMEText
+from email.MIMEMultipart import MIMEMultipart
import core
import utils
@@ -69,74 +72,60 @@ class SMTP(object):
:param: cfg (string) path of the configuration file.
"""
- # define a set of default values
- DEFAULT_CONFIG_FILE = 'smtp.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'smtp.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
cfg = DEFAULT_CONFIG_FILE
- config.read(cfg)
+ try:
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
self.our_domain = config.get('general', 'our_domain')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'our_domain' from 'general'")
+ self.mirrors = config.get('general', 'mirrors')
+ self.i18ndir = config.get('i18n', 'dir')
- try:
- core_cfg = config.get('general', 'core_cfg')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'core_cfg' from 'general'")
+ logdir = config.get('log', 'dir')
+ logfile = os.path.join(logdir, 'smtp.log')
+ loglevel = config.get('log', 'level')
- try:
blacklist_cfg = config.get('blacklist', 'cfg')
self.bl = blacklist.Blacklist(blacklist_cfg)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'cfg' from 'blacklist'")
-
- try:
self.bl_max_req = config.get('blacklist', 'max_requests')
self.bl_max_req = int(self.bl_max_req)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'max_requests' from 'blacklist'")
-
- try:
self.bl_wait_time = config.get('blacklist', 'wait_time')
self.bl_wait_time = int(self.bl_wait_time)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'wait_time' from 'blacklist'")
- try:
- self.i18ndir = config.get('i18n', 'dir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'i18n'")
+ core_cfg = config.get('general', 'core_cfg')
+ self.core = core.Core(core_cfg)
- try:
- logdir = config.get('log', 'dir')
- logfile = os.path.join(logdir, 'smtp.log')
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
+ raise ConfigError("Configuration error: %s" % str(e))
+ except blacklist.ConfigError as e:
+ raise InternalError("Blacklist error: %s" % str(e))
+ except core.ConfigError as e:
+ raise InternalError("Core error: %s" % str(e))
- try:
- loglevel = config.get('log', 'level')
- except ConfigParser.Error as e:
- raise ConfigurationError("Couldn't read 'level' from 'log'")
+ # logging
+ log = logging.getLogger(__name__)
- # use default values
- self.core = core.Core(core_cfg)
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ log.info('Redirecting SMTP logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def _is_blacklisted(self, addr):
"""Check if a user is blacklisted.
@@ -148,8 +137,9 @@ class SMTP(object):
"""
try:
- self.bl.is_blacklisted(addr, 'SMTP', self.bl_max_req,
- self.bl_wait_time)
+ self.bl.is_blacklisted(
+ addr, 'SMTP', self.bl_max_req, self.bl_wait_time
+ )
return False
except blacklist.BlacklistError as e:
return True
@@ -228,11 +218,14 @@ class SMTP(object):
"""
# obtain the content in the proper language
- t = gettext.translation(lc, self.i18ndir, languages=[lc])
- _ = t.ugettext
+ try:
+ t = gettext.translation(lc, self.i18ndir, languages=[lc])
+ _ = t.ugettext
- msgstr = _(msgid)
- return msgstr
+ msgstr = _(msgid)
+ return msgstr
+ except IOError as e:
+ raise ConfigError("%s" % str(e))
def _parse_email(self, msg, addr):
"""Parse the email received.
@@ -270,17 +263,23 @@ class SMTP(object):
# core knows what OS are supported
supported_os = self.core.get_supported_os()
- # if no OS is found, help request by default
- found_os = False
+ # search for OS or mirrors request
+ # if nothing is found, help by default
+ found_request = False
lines = msg.split(' ')
for word in lines:
- if not found_os:
+ if not found_request:
+ # OS first
for os in supported_os:
if re.match(os, word, re.IGNORECASE):
req['os'] = os
req['type'] = 'links'
- found_os = True
+ found_request = True
break
+ # mirrors
+ if re.match("mirrors?", word, re.IGNORECASE):
+ req['type'] = 'mirrors'
+ found_request = True
else:
break
return req
@@ -298,15 +297,18 @@ class SMTP(object):
:return: (object) the email object.
"""
- email_obj = MIMEText(msg)
+ email_obj = MIMEMultipart()
email_obj.set_charset("utf-8")
email_obj['Subject'] = subject
email_obj['From'] = from_addr
email_obj['To'] = to_addr
+ msg_attach = MIMEText(msg, 'text')
+ email_obj.attach(msg_attach)
+
return email_obj
- def _send_email(self, from_addr, to_addr, subject, msg):
+ def _send_email(self, from_addr, to_addr, subject, msg, attach=None):
"""Send an email.
Take a 'from' and 'to' addresses, a subject and the content, creates
@@ -316,10 +318,27 @@ class SMTP(object):
:param: to_addr (string) the address of the recipient.
:param: subject (string) the subject of the email.
:param: msg (string) the content of the email.
+ :param: attach (string) the path of the mirrors list.
"""
email_obj = self._create_email(from_addr, to_addr, subject, msg)
+ if(attach):
+ # for now, the only email with attachment is the one for mirrors
+ try:
+ part = MIMEBase('application', "octet-stream")
+ part.set_payload(open(attach, "rb").read())
+ Encoders.encode_base64(part)
+
+ part.add_header(
+ 'Content-Disposition',
+ 'attachment; filename="mirrors.txt"'
+ )
+
+ email_obj.attach(part)
+ except IOError as e:
+ raise SendEmailError('Error with mirrors: %s' % str(e))
+
try:
s = smtplib.SMTP("localhost")
s.sendmail(from_addr, to_addr, email_obj.as_string())
@@ -341,17 +360,25 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
- links_subject = self._get_msg('links_subject', lc)
- links_msg = self._get_msg('links_msg', lc)
- links_msg = links_msg % (os, lc, links)
-
try:
- self._send_email(from_addr, to_addr, links_subject, links_msg)
+ links_subject = self._get_msg('links_subject', lc)
+ links_msg = self._get_msg('links_msg', lc)
+ links_msg = links_msg % (os, lc, links)
+
+ self._send_email(
+ from_addr,
+ to_addr,
+ links_subject,
+ links_msg,
+ None
+ )
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
raise InternalError("Error while sending links message")
- def _send_help(self, lc, from_addr, to_addr):
- """Send help message.
+ def _send_mirrors(self, lc, from_addr, to_addr):
+ """Send mirrors message.
Get the message in the proper language (according to the locale),
replace variables (if any) and send the email.
@@ -362,37 +389,39 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
- help_subject = self._get_msg('help_subject', lc)
- help_msg = self._get_msg('help_msg', lc)
-
try:
- self._send_email(from_addr, to_addr, help_subject, help_msg)
+ mirrors_subject = self._get_msg('mirrors_subject', lc)
+ mirrors_msg = self._get_msg('mirrors_msg', lc)
+
+ self._send_email(
+ from_addr, to_addr, mirrors_subject, mirrors_msg, self.mirrors
+ )
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
- raise InternalError("Error while sending help message")
+ raise InternalError("Error while sending mirrors message")
- def _send_unsupported_lc(self, lc, os, from_addr, to_addr):
- """Send unsupported locale message.
+ def _send_help(self, lc, from_addr, to_addr):
+ """Send help message.
- Get the message for unsupported locale in english, replace variables
- (if any) and send the email.
+ Get the message in the proper language (according to the locale),
+ replace variables (if any) and send the email.
:param: lc (string) the locale.
- :param: os (string) the operating system.
:param: from_addr (string) the address of the sender.
:param: to_addr (string) the address of the recipient.
"""
-
- # obtain the content in english and send it
- un_lc_subject = self._get_msg('unsupported_lc_subject', 'en')
- un_lc_msg = self._get_msg('unsupported_lc_msg', 'en')
- un_lc_msg = un_lc_msg % lc
-
+ # obtain the content in the proper language and send it
try:
- self._send_email(from_addr, to_addr, un_lc_subject, un_lc_msg)
+ help_subject = self._get_msg('help_subject', lc)
+ help_msg = self._get_msg('help_msg', lc)
+ self._send_email(from_addr, to_addr, help_subject, help_msg, None)
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
- raise InternalError("Error while sending unsupported lc message")
+ raise InternalError("Error while sending help message")
def process_email(self, raw_msg):
"""Process the email received.
@@ -411,6 +440,7 @@ class SMTP(object):
links to the Core module.
"""
+ self.log.debug("Processing email")
parsed_msg = email.message_from_string(raw_msg)
content = self._get_content(parsed_msg)
from_addr = parsed_msg['From']
@@ -423,71 +453,96 @@ class SMTP(object):
# two ways for a request to be bogus: address malformed or
# blacklisted
try:
+ self.log.debug("Normalizing address...")
norm_from_addr = self._get_normalized_address(from_addr)
except AddressError as e:
status = 'malformed'
bogus_request = True
+ self.log.debug("Address is malformed!")
# it might be interesting to know what triggered this
# we are not logging this for now
# logfile = self._log_email('malformed', content)
if norm_from_addr:
+ self.log.debug("Anonymizing address...")
anon_addr = utils.get_sha256(norm_from_addr)
if self._is_blacklisted(anon_addr):
status = 'blacklisted'
bogus_request = True
+ self.log.debug("Address is blacklisted!")
# it might be interesting to know extra info
# we are not logging this for now
# logfile = self._log_email(anon_addr, content)
if not bogus_request:
# try to figure out what the user is asking
+ self.log.debug("Request seems legit; parsing it...")
req = self._parse_email(content, to_addr)
# our address should have the locale requested
our_addr = "gettor+%s@%s" % (req['lc'], self.our_domain)
+ self.log.debug("Replying from %s" % our_addr)
- # two possible options: asking for help or for the links
+ # possible options: help, links, mirrors
if req['type'] == 'help':
+ self.log.debug("Type of request: help")
+ self.log.debug("Trying to send help...")
# make sure we can send emails
try:
self._send_help(req['lc'], our_addr, norm_from_addr)
+ status = 'success'
except SendEmailError as e:
status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
raise InternalError("Something's wrong with the SMTP "
"server: %s" % str(e))
- elif req['type'] == 'links':
+ elif req['type'] == 'mirrors':
+ self.log.debug("Type of request: mirrors")
+ self.log.debug("Trying to send the mirrors...")
+ # make sure we can send emails
try:
- links = self.core.get_links('SMTP', req['os'],
- req['lc'])
-
- except core.UnsupportedLocaleError as e:
- # if we got here, the address of the sender should
- # be valid so we send him/her a message about the
- # unsupported locale
- status = 'unsupported_lc'
- self._send_unsupported_lc(req['lc'], req['os'],
- our_addr, norm_from_addr)
- return
+ self._send_mirrors(req['lc'], our_addr, norm_from_addr)
+ status = 'success'
+ except SendEmailError as e:
+ status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
+ raise SendEmailError("Something's wrong with the SMTP "
+ "server: %s" % str(e))
+ elif req['type'] == 'links':
+ self.log.debug("Type of request: links")
+ self.log.debug("Trying to obtain the links...")
+ try:
+ links = self.core.get_links(
+ 'SMTP', req['os'], req['lc']
+ )
# if core fails, we fail too
except (core.InternalError, core.ConfigurationError) as e:
status = 'core_error'
+ self.log.debug("FAILED: %s" % str(e))
# something went wrong with the core
raise InternalError("Error obtaining the links")
# make sure we can send emails
+ self.log.debug("Trying to send the links...")
try:
self._send_links(links, req['lc'], req['os'], our_addr,
norm_from_addr)
+ status = 'success'
except SendEmailError as e:
status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
raise SendEmailError("Something's wrong with the SMTP "
"server: %s" % str(e))
- status = 'success'
+ self.log.debug("Mail sent!")
finally:
# keep stats
if req:
- self.core.add_request_to_db()
+ self.log.debug("Adding request to database... ")
+ try:
+ self.core.add_request_to_db()
+ self.log.debug("Request added")
+ except InternalError as e:
+ self.log.debug("FAILED: %s" % str(e))
diff --git a/lang/smtp/i18n/en/LC_MESSAGES/en.po b/lang/smtp/i18n/en/LC_MESSAGES/en.po
index 906dbb8..dcb2e35 100644
--- a/lang/smtp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/smtp/i18n/en/LC_MESSAGES/en.po
@@ -4,6 +4,10 @@ domain "en"
msgid "links_subject"
msgstr "[GetTor] Links for your request"
+#: Mirrors subject
+msgid "mirrors_subject"
+msgstr "[GetTor] Mirrors"
+
#: Help subject
msgid "help_subject"
msgstr "[GetTor] Help"
@@ -32,6 +36,21 @@ network, or need to talk to a human, please contact our support team at:\n\
We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
French and Spanish."
+#: Mirrors message
+msgid "mirrors_msg"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. Attached to this email you will find\n\
+an updated list of mirrors of Tor Project's website.\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
+
#: Help message
msgid "help_msg"
msgstr "Hello there! this is the 'GetTor' robot.\n\
diff --git a/mirrors-list.txt b/mirrors-list.txt
new file mode 100644
index 0000000..311a3a5
--- /dev/null
+++ b/mirrors-list.txt
@@ -0,0 +1,58 @@
+https://tor-mirror.de/ - by tor-mirror.de (Germany)
+https://tor.blingblingsquad.net/ - by [[:bbs:]] (Germany)
+https://tor.li/ - by Tor Supporter (Estonia)
+https://tormirror.tb-itf-tor.de - by TB-ITF (Germany)
+https://tormirror.piratenpartei-bayern.de - by Piratenpartei Bayern (Germany)
+https://tor.hoi-polloi.org/ - by Tor Supporter (Germany)
+https://tor.fodt.it - by FoDT.it (Austria)
+https://tor.zilog.es/ - by Tor Supporter (Spain)
+https://199.175.55.215/ - by Tor Supporter (United States)
+https://2607:8b00:2::6258:5c9/ - by Tor Supporter (United States)
+https://tor.spline.inf.fu-berlin.de/ - by spline (Germany)
+https://fbnaia.homelinux.net/torproject/ - by Tor Supporter (Mexico)
+https://mirror.unicorncloud.org/torproject.org/ - by UnicornCloud.org (Germany)
+https://tor.hackthissite.org/ - by HackThisSite.org (United States)
+https://tor.crazyhaze.de/ - by crazyhaze.de (Germany)
+https://creep.im/tor - by Soviet Anonymous (Russia)
+https://www.torservers.net/mirrors/torproject.org/ - by torservers (Germany)
+https://mirror.torland.me/torproject.org/ - by torland (United Kingdom)
+https://tor.myrl.net/ - by myRL.net (Iceland)
+https://torprojekt.userzap.de - by Userzap (Germany)
+https://tor.stalkr.net/ - by stalkr.net (France)
+https://tor-mirror.cyberguerrilla.org - by cYbergueRrilLa AnonyMous NeXus (Germany)
+https://torproject.gtor.org/ - by Gtor (Germany)
+https://torproject.nexiom.net - by SDL (United States)
+https://mirror.velcommuta.de/tor/ - by Tor Supporter (Germany)
+https://tor.eff.org - by EFF (United States)
+https://tor.void.gr - by Tor Supporter (Greece)
+https://reichster.de/mirrors/torproject.org - by Tor Supporter (Germany)
+https://tor.miglix.eu - by Tor Supporter (Germany)
+https://tor.fr33tux.org - by Tor Supporter (France)
+https://tor.iv.net.pl - by Sebastian M. Bobrecki (Poland)
+https://tor.static.lu - by d0wn.biz (France)
+https://www.moparisthebest.com/tor/ - by moparisthebest.com (Germany)
+https://ayo.tl/tor/ - by Tor Supporter (Iceland)
+https://tor.pajonzeck.de/ - by ITsn (Germany)
+https://tor.ludikovsky.name/ - by Tor Supporter (Austria)
+https://tor.nuclear-weapons.net - by Setec Administrator (Texas)
+https://tor.calyxinstitute.org - by The Calyx Institute (United States)
+https://mirror2.babylon.network/torproject/ - by Babylon Network (The Netherlands)
+https://mirror0.babylon.network/torproject/ - by Babylon Network (France)
+https://mirror1.babylon.network/torproject/ - by Babylon Network (France)
+https://tor.ybti.net/ - by Tor Supporter (Germany)
+https://tor.0x3d.lu/ - by 0x3d.lu (Germany)
+https://www.unicorncloud.org/public/torproject.org/ - by UnicornCloud.org (Favoriten)
+https://108.248.87.242/ - by intfxdx.com (United States)
+https://mirrors.samwhited.net/tor - by SamWhited.com (GA)
+https://www.jessevictors.com/secureMirrors/torproject.org/ - by Department of CS at USU (United States)
+https://mirror.ntzk.de/torproject.org/ - by Netzkonstrukt Berlin (Germany)
+https://www.eprci.com/tor/ - by EPRCI (NH)
+https://tor-mirror.kura.io/ - by KURA IO LIMITED (Netherlands)
+https://www.it-sicherheitschannel.de/ - by PW (Germany)
+https://tor.freedom.press - by Freedom of the Press Foundation (US)
+https://tor.hoovism.com/ - by Matthew Hoover (NJ)
+https://torproject.urown.net/ - by urown.net (Switzerland)
+https://sela.io/mirrors/torproject.org/ - by sela Internet (Germany)
+https://services.justaguy.pw/ - by Justaguy (The Netherlands)
+https://tor.thecthulhu.com/ - by TheCthulhu (The Netherlands)
+https://tor.ccc.de - by CCC (The Netherlands)
diff --git a/smtp.cfg b/smtp.cfg
index 671c090..a7e9f7a 100644
--- a/smtp.cfg
+++ b/smtp.cfg
@@ -1,5 +1,6 @@
[general]
basedir: /path/to/gettor/smtp
+mirrors: /path/to/mirrors
our_domain: torproject.org
core_cfg: /path/to/core.cfg
@@ -13,4 +14,4 @@ dir: /path/to/i18n/
[log]
level: DEBUG
-dir: /path/to/log/
\ No newline at end of file
+dir: /path/to/log/
diff --git a/tor-mirrors b/tor-mirrors
new file mode 100644
index 0000000..5dbd421
--- /dev/null
+++ b/tor-mirrors
@@ -0,0 +1,2187 @@
+[
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.loritsu.com/dist/",
+ "httpWebsiteMirror": "http://tor.loritsu.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.adamas.ai/dist/",
+ "httpWebsiteMirror": "http://torproject.adamas.ai/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "LU",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "LU",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Luxemborg",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torua.reactor-xg.kiev.ua/dist/",
+ "httpWebsiteMirror": "http://torua.reactor-xg.kiev.ua/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "UA",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "UA",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Ukraine",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://37.187.0.127/tormirror/dist/",
+ "httpWebsiteMirror": "http://37.187.0.127/tormirror/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.minibofh.org/dist/",
+ "httpWebsiteMirror": "http://tor.minibofh.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mage.me.uk/dist/",
+ "httpWebsiteMirror": "http://tor.mage.me.uk/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "UK",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "UK",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United Kingdom",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "nsane2307 eml cc",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.de/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.de/",
+ "httpsDistMirror": "https://tor-mirror.de/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "tor-mirror.de",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "citizen428 AT gmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.blingblingsquad.net/dist/",
+ "httpWebsiteMirror": "http://tor.blingblingsquad.net/",
+ "httpsDistMirror": "https://tor.blingblingsquad.net/dist/",
+ "httpsWebsiteMirror": "https://tor.blingblingsquad.net/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "[[:bbs:]]",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.nwlinux.us/dist/",
+ "httpWebsiteMirror": "http://torproject.nwlinux.us/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "NW Linux",
+ "region": "US",
+ "rsyncDistMirror": "rsync://nwlinux.us/tor-dist",
+ "rsyncWebsiteMirror": "rsync://nwlinux.us/tor-web",
+ "subRegion": "WA",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://www.coevoet.nl/tor/dist/",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.taiga-san.net/dist/",
+ "httpWebsiteMirror": "http://tor.taiga-san.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "LazyTiger",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.li/dist/",
+ "httpWebsiteMirror": "http://tor.li/",
+ "httpsDistMirror": "https://tor.li/dist/",
+ "httpsWebsiteMirror": "https://tor.li/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "EE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "EE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Estonia",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.externenpr\u00fcfung-nichtsch\u00fcler.de/dist/",
+ "httpWebsiteMirror": "http://tor.externenpr\u00fcfung-nichtsch\u00fcler.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "mirror-service(a)netcologne.de",
+ "ftpWebsiteMirror": "ftp://mirror.netcologne.de/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.netcologne.de/torproject.org/dist",
+ "httpWebsiteMirror": "http://mirror.netcologne.de/torproject.org",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "NetCologne GmbH",
+ "region": "",
+ "rsyncDistMirror": "rsync://mirror.netcologne.de/torproject.org/dist",
+ "rsyncWebsiteMirror": "rsync://mirror.netcologne.de/torproject.org",
+ "subRegion": "NRW",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin AT netgull DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.netgull.com/torproject/",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "NetGull",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "mirrors[at]ip-connect[dot]vn[dot]ua",
+ "ftpWebsiteMirror": "ftp://torproject.ip-connect.vn.ua/mirror/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ip-connect.vn.ua/dist",
+ "httpWebsiteMirror": "http://torproject.ip-connect.vn.ua",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "UA",
+ "loadBalanced": "Yes",
+ "orgName": "IP-Connect LLC",
+ "region": "",
+ "rsyncDistMirror": "rsync://torproject.ip-connect.vn.ua/torproject/dist",
+ "rsyncWebsiteMirror": "rsync://torproject.ip-connect.vn.ua/torproject",
+ "subRegion": "VN",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "torsupport AT tb-itf DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.tb-itf-tor.de/dist/",
+ "httpWebsiteMirror": "http://tormirror.tb-itf-tor.de",
+ "httpsDistMirror": "https://tormirror.tb-itf-tor.de/dist/",
+ "httpsWebsiteMirror": "https://tormirror.tb-itf-tor.de",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "TB-ITF",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin at koreswatanabe dottnet",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-relay.koreswatanabe.net/dist/",
+ "httpWebsiteMirror": "http://tor-relay.koreswatanabe.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "RO",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "RO",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Romania",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "calebcenter(a)live.com",
+ "ftpWebsiteMirror": "ftp://ftp.calebxu.tk",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.calebxu.tk/dist",
+ "httpWebsiteMirror": "http://tor.calebxu.tk",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "calebxu.tk",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "rsync://calebxu.tk/tor",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "maki(a)maki-chan.de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirrors.maki-chan.de/dist/",
+ "httpWebsiteMirror": "http://tor.mirrors.maki-chan.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Maki Hoshisawa",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Sat Aug 23 08:09:07 2014"
+ },
+ {
+ "adminContact": "info AT zentrum-der-gesundheit DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.idnr.ws/dist/",
+ "httpWebsiteMirror": "http://tor.idnr.ws/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DK",
+ "loadBalanced": "No",
+ "orgName": "Zentrum der Gesundheit",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Denmark",
+ "updateDate\n": "Tue Sep 2 11:16:00 2014"
+ },
+ {
+ "adminContact": "info /AT enn /DOT lu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://btn6gqzqevlhoryd.onion",
+ "httpDistMirror": "http://torproject.lu/dist/",
+ "httpWebsiteMirror": "http://torproject.lu/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "Frenn vun der Enn A.S.B.L.",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Piratenpartei Bayern",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.piratenpartei-bayern.de/dist/",
+ "httpWebsiteMirror": "http://tormirror.piratenpartei-bayern.de",
+ "httpsDistMirror": "https://tormirror.piratenpartei-bayern.de/dist/",
+ "httpsWebsiteMirror": "https://tormirror.piratenpartei-bayern.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Piratenpartei Bayern",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.hoi-polloi.org/dist/",
+ "httpWebsiteMirror": "http://tor.hoi-polloi.org",
+ "httpsDistMirror": "https://tor.hoi-polloi.org/dist/",
+ "httpsWebsiteMirror": "https://tor.hoi-polloi.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)fodt.it // FoDT.it Webteam",
+ "ftpWebsiteMirror": "ftp://ftp.fodt.it/pub/mirrors/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.fodt.it/dist/",
+ "httpWebsiteMirror": "http://tor.fodt.it",
+ "httpsDistMirror": "https://tor.fodt.it/dist/",
+ "httpsWebsiteMirror": "https://tor.fodt.it",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "FoDT.it",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Mon Aug 25 10:19:07 2014"
+ },
+ {
+ "adminContact": "http://www.multinet.no",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.multinet.no/dist/",
+ "httpWebsiteMirror": "http://tor.multinet.no/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NO",
+ "loadBalanced": "No",
+ "orgName": "MultiNet AS",
+ "region": "Trondheim",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Trondheim",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "haskell at gmx.es",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.zilog.es/dist/",
+ "httpWebsiteMirror": "http://tor.zilog.es/",
+ "httpsDistMirror": "https://tor.zilog.es/dist/",
+ "httpsWebsiteMirror": "https://tor.zilog.es/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "ES",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Spain",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://199.175.55.215/dist/",
+ "httpWebsiteMirror": "http://199.175.55.215/",
+ "httpsDistMirror": "https://199.175.55.215/dist/",
+ "httpsWebsiteMirror": "https://199.175.55.215/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://2607:8b00:2::6258:5c9/dist/",
+ "httpWebsiteMirror": "http://2607:8b00:2::6258:5c9/",
+ "httpsDistMirror": "https://2607:8b00:2::6258:5c9/dist/",
+ "httpsWebsiteMirror": "https://2607:8b00:2::6258:5c9/",
+ "ipv4": "FALSE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "margus.random at mail.ee",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://cyberside.net.ee/tor/",
+ "httpWebsiteMirror": "http://cyberside.planet.ee/tor/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "EE",
+ "loadBalanced": "No",
+ "orgName": "CyberSIDE",
+ "region": "EE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Estonia",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.torproject.is/dist/",
+ "httpWebsiteMirror": "http://www.torproject.is/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "torproject.is",
+ "region": "IS",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "ftp://ftp.spline.de/pub/tor",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.spline.de/dist/",
+ "httpWebsiteMirror": "http://tor.spline.de/",
+ "httpsDistMirror": "https://tor.spline.inf.fu-berlin.de/dist/",
+ "httpsWebsiteMirror": "https://tor.spline.inf.fu-berlin.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "spline",
+ "region": "DE",
+ "rsyncDistMirror": "rsync://ftp.spline.de/tor/dist",
+ "rsyncWebsiteMirror": "rsync://ftp.spline.de/tor",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.me0w.cc/dist/",
+ "httpWebsiteMirror": "http://tor.me0w.cc/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "RO",
+ "loadBalanced": "No",
+ "orgName": "me0w.cc",
+ "region": "RO",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Romania",
+ "updateDate\n": "Thu Jan 1 16:17:56 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.borgmann.tv/dist/",
+ "httpWebsiteMirror": "http://tor.borgmann.tv/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "borgmann.tv",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Sun Jul 12 19:04:44 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.dont-know-me.at/dist/",
+ "httpWebsiteMirror": "http://tor.dont-know-me.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "coralcdn.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.torproject.org.nyud.net/dist/",
+ "httpWebsiteMirror": "http://www.torproject.org.nyud.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "INT",
+ "loadBalanced": "Yes",
+ "orgName": "CoralCDN",
+ "region": "INT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "International",
+ "updateDate\n": "Thu Jan 8 02:01:06 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ph3x.at/dist/",
+ "httpWebsiteMirror": "http://torproject.ph3x.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://fbnaia.homelinux.net/torproject/dist/",
+ "httpWebsiteMirror": "http://fbnaia.homelinux.net/torproject/",
+ "httpsDistMirror": "https://fbnaia.homelinux.net/torproject/dist/",
+ "httpsWebsiteMirror": "https://fbnaia.homelinux.net/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "MX",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "MX",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Mexico",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "webmaster AT askapache DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.askapache.com/dist/",
+ "httpWebsiteMirror": "http://tor.askapache.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "AskApache",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "California",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirror.chekanov.net/dist/",
+ "httpWebsiteMirror": "http://tor.mirror.chekanov.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "kontakt AT unicorncloud DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.unicorncloud.org/torproject.org/dist",
+ "httpWebsiteMirror": "http://mirror.unicorncloud.org/torproject.org/",
+ "httpsDistMirror": "https://mirror.unicorncloud.org/torproject.org/dist",
+ "httpsWebsiteMirror": "https://mirror.unicorncloud.org/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "UnicornCloud.org",
+ "region": "Falkenstein",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "root AT amorphis DOT eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.amorphis.eu/dist/",
+ "httpWebsiteMirror": "http://tor.amorphis.eu/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Amorphis",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "hackthissite.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.hackthissite.org/tor",
+ "httpWebsiteMirror": "http://tor.hackthissite.org/",
+ "httpsDistMirror": "https://mirror.hackthissite.org/tor",
+ "httpsWebsiteMirror": "https://tor.hackthissite.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "HackThisSite.org",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "paul at coffswifi.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.coffswifi.net/dist",
+ "httpWebsiteMirror": "http://torproject.coffswifi.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AU",
+ "loadBalanced": "No",
+ "orgName": "CoffsWiFi",
+ "region": "APNIC",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Australia and New Zealand",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "http://tor.cyberarmy.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "cyberarmy",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "hostmaster AT example DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.theonionrouter.com/dist/",
+ "httpWebsiteMirror": "http://www.theonionrouter.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "TheOnionRouter",
+ "region": "Iceland",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.crazyhaze.de/dist/",
+ "httpWebsiteMirror": "http://tor.crazyhaze.de/",
+ "httpsDistMirror": "https://tor.crazyhaze.de/dist/",
+ "httpsWebsiteMirror": "https://tor.crazyhaze.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "crazyhaze.de",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jul 7 13:16:29 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirrors.chaos-darmstadt.de/tor-mirror/dist/",
+ "httpWebsiteMirror": "http://mirrors.chaos-darmstadt.de/tor-mirror/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "chaos darmstadt",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "ftp://creep.im/mirrors/tor",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://creep.im/tor/dist/",
+ "httpWebsiteMirror": "http://creep.im/tor",
+ "httpsDistMirror": "https://creep.im/tor/dist/",
+ "httpsWebsiteMirror": "https://creep.im/tor",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "RU",
+ "loadBalanced": "No",
+ "orgName": "Soviet Anonymous",
+ "region": "RU",
+ "rsyncDistMirror": "rsync://creep.im/tor-dist",
+ "rsyncWebsiteMirror": "rsync://creep.im/tor",
+ "subRegion": "Russia",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://hbpvnydyyjbmhx6b.onion/mirrors/torproject.org/",
+ "httpDistMirror": "http://www.torservers.net/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://www.torservers.net/mirrors/torproject.org/",
+ "httpsDistMirror": "https://www.torservers.net/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://www.torservers.net/mirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "torservers",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.torland.me/torproject.org/dist/",
+ "httpWebsiteMirror": "http://mirror.torland.me/torproject.org/",
+ "httpsDistMirror": "https://mirror.torland.me/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://mirror.torland.me/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "GB",
+ "loadBalanced": "No",
+ "orgName": "torland",
+ "region": "GB",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United Kingdom",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.lightning-bolt.net/dist/",
+ "httpWebsiteMirror": "http://torproject.lightning-bolt.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "CZ",
+ "loadBalanced": "No",
+ "orgName": "Lightning-bolt.net",
+ "region": "CZ",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Czech Republic",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "IceBear",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.myrl.net/dist/",
+ "httpWebsiteMirror": "http://tor.myrl.net/",
+ "httpsDistMirror": "https://tor.myrl.net/dist/",
+ "httpsWebsiteMirror": "https://tor.myrl.net/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "myRL.net",
+ "region": "IS",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kiro AT userzap DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torprojekt.userzap.de/dist/",
+ "httpWebsiteMirror": "http://torprojekt.userzap.de",
+ "httpsDistMirror": "https://torprojekt.userzap.de/dist/",
+ "httpsWebsiteMirror": "https://torprojekt.userzap.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Userzap",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "tor(a)les.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.les.net/dist",
+ "httpWebsiteMirror": "http://tor.les.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "CA",
+ "loadBalanced": "NO",
+ "orgName": "tor(a)les.net",
+ "region": "CA",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Canada",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)stalkr.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.stalkr.net/dist/",
+ "httpWebsiteMirror": "http://tor.stalkr.net/",
+ "httpsDistMirror": "https://tor.stalkr.net/dist/",
+ "httpsWebsiteMirror": "https://tor.stalkr.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "NO",
+ "orgName": "stalkr.net",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "doemela[AT]cyberguerrilla[DOT]org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://6dvj6v5imhny3anf.onion",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://tor-mirror.cyberguerrilla.org/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.cyberguerrilla.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "cYbergueRrilLa AnonyMous NeXus",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "contact(a)gtor.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.gtor.org/dist/",
+ "httpWebsiteMirror": "http://torproject.gtor.org/",
+ "httpsDistMirror": "https://torproject.gtor.org/dist/",
+ "httpsWebsiteMirror": "https://torproject.gtor.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Gtor",
+ "region": "DE",
+ "rsyncDistMirror": "rsync://torproject.gtor.org/website-mirror/dist/",
+ "rsyncWebsiteMirror": "rsync://torproject.gtor.org/website-mirror/",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "SDL",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.nexiom.net",
+ "httpWebsiteMirror": "http://torproject.nexiom.net",
+ "httpsDistMirror": "https://torproject.nexiom.net/dist",
+ "httpsWebsiteMirror": "https://torproject.nexiom.net",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "SDL",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.velcommuta.de/tor/dist/",
+ "httpWebsiteMirror": "http://mirror.velcommuta.de/tor/",
+ "httpsDistMirror": "https://mirror.velcommuta.de/tor/dist/",
+ "httpsWebsiteMirror": "https://mirror.velcommuta.de/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "EFF",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://tor.eff.org/dist/",
+ "httpsWebsiteMirror": "https://tor.eff.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "EFF",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.void.gr/dist/",
+ "httpWebsiteMirror": "http://tor.void.gr",
+ "httpsDistMirror": "https://tor.void.gr/dist/",
+ "httpsWebsiteMirror": "https://tor.void.gr",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "GR",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "GR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Greece",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Ich Eben",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://reichster.de/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://reichster.de/mirrors/torproject.org/",
+ "httpsDistMirror": "https://reichster.de/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://reichster.de/mirrors/torproject.org",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "jlgaddis AT gnu DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor1.evilrouters.net/dist/",
+ "httpWebsiteMirror": "http://tor1.evilrouters.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Evil Routers",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor AT miglix DOT eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.miglix.eu/dist/",
+ "httpWebsiteMirror": "http://tor.miglix.eu",
+ "httpsDistMirror": "https://tor.miglix.eu/dist/",
+ "httpsWebsiteMirror": "https://tor.miglix.eu",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor TA ninurta TOD name",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ninurta.name/dist/",
+ "httpWebsiteMirror": "http://tor.ninurta.name/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "no",
+ "orgName": "TorNinurtaName",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Oct 22 15:02:17 2014"
+ },
+ {
+ "adminContact": "fr33tux <AT> general-changelog-team.fr",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.fr33tux.org/dist/",
+ "httpWebsiteMirror": "http://tor.fr33tux.org",
+ "httpsDistMirror": "https://tor.fr33tux.org/dist/",
+ "httpsWebsiteMirror": "https://tor.fr33tux.org",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "sebastian(at)bobrecki(dot)pl",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.iv.net.pl/dist/",
+ "httpWebsiteMirror": "http://tor.iv.net.pl",
+ "httpsDistMirror": "https://tor.iv.net.pl/dist/",
+ "httpsWebsiteMirror": "https://tor.iv.net.pl",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "PL",
+ "loadBalanced": "No",
+ "orgName": "Sebastian M. Bobrecki",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Poland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor-mirror AT rdns DOT cc",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.static.lu/dist/",
+ "httpWebsiteMirror": "http://tor.static.lu",
+ "httpsDistMirror": "https://tor.static.lu/dist/",
+ "httpsWebsiteMirror": "https://tor.static.lu",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "d0wn.biz",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)moparisthebest.com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.moparisthebest.com/tor/dist/",
+ "httpWebsiteMirror": "http://www.moparisthebest.com/tor/",
+ "httpsDistMirror": "https://www.moparisthebest.com/tor/dist/",
+ "httpsWebsiteMirror": "https://www.moparisthebest.com/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "moparisthebest.com",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Sebastian",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.maxanoo.com/dist/",
+ "httpWebsiteMirror": "http://tor.maxanoo.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "NO",
+ "orgName": "Maxanoo",
+ "region": "Amsterdam",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Sun May 31 15:13:53 2015"
+ },
+ {
+ "adminContact": "rorrim AT ayo DOT tl",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://ayo.tl/tor/dist/",
+ "httpWebsiteMirror": "http://ayo.tl/tor/",
+ "httpsDistMirror": "https://ayo.tl/tor/dist/",
+ "httpsWebsiteMirror": "https://ayo.tl/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "stefano.fenoglio AT gmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.stefanof.com/dist",
+ "httpWebsiteMirror": "http://tor.stefanof.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Italy",
+ "updateDate\n": "Sun Jul 12 13:19:35 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ramosresearch.com/dist/",
+ "httpWebsiteMirror": "http://tor.ramosresearch.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Ramos Research",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.euve33747.vserver.de/dist",
+ "httpWebsiteMirror": "http://tor.euve33747.vserver.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "s7r[at]sky-ip[d0t]org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://beautiful-mind.sky-ip.org/dist/",
+ "httpWebsiteMirror": "http://beautiful-mind.sky-ip.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "sky-ip.org",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor#pajonzeck#de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://zgfgvob256pffy62.onion",
+ "httpDistMirror": "http://tor.pajonzeck.de/dist/",
+ "httpWebsiteMirror": "http://tor.pajonzeck.de/",
+ "httpsDistMirror": "https://tor.pajonzeck.de/dist/",
+ "httpsWebsiteMirror": "https://tor.pajonzeck.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "ITsn",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor.pajonzeck.de/tor/dist",
+ "rsyncWebsiteMirror": "rsync://tor.pajonzeck.de/tor",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "peter AT ludikovsky DOT name",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://54lnbzjo6xlr4f4j.onion/",
+ "httpDistMirror": "http://tor.ludikovsky.name/dist",
+ "httpWebsiteMirror": "http://tor.ludikovsky.name/",
+ "httpsDistMirror": "https://tor.ludikovsky.name/dist",
+ "httpsWebsiteMirror": "https://tor.ludikovsky.name/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor.ludikovsky.name/tor-dist",
+ "rsyncWebsiteMirror": "rsync://tor.ludikovsky.name/tor",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin AT nuclear DASH weapons DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.nuclear-weapons.net/dist",
+ "httpWebsiteMirror": "http://tor.nuclear-weapons.net",
+ "httpsDistMirror": "https://tor.nuclear-weapons.net/dist",
+ "httpsWebsiteMirror": "https://tor.nuclear-weapons.net",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Setec Administrator",
+ "region": "Austin",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Texas",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "0x43DE8191",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.hactar.bz/dist/",
+ "httpWebsiteMirror": "http://torproject.hactar.bz",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "-nick at calyx dot com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://tmdrhl4e4anhsjc5.onion",
+ "httpDistMirror": "http://tor.calyxinstitute.org/dist/",
+ "httpWebsiteMirror": "http://tor.calyxinstitute.org",
+ "httpsDistMirror": "https://tor.calyxinstitute.org/dist/",
+ "httpsWebsiteMirror": "https://tor.calyxinstitute.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "The Calyx Institute",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "opi(a)zeropi.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.zeropi.net/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.zeropi.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Mon Dec 1 12:15:20 2014"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror2.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror2.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror2.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror2.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror2.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror2.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror2.babylon.network/torproject/",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror0.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror0.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror0.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror0.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror0.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror0.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror0.babylon.network/torproject/",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror1.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror1.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror1.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror1.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror1.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror1.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror1.babylon.network/torproject/",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "alexander AT dietrich DOT cx",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ybti.net/dist/",
+ "httpWebsiteMirror": "http://tor.ybti.net/",
+ "httpsDistMirror": "https://tor.ybti.net/dist/",
+ "httpsWebsiteMirror": "https://tor.ybti.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)0x3d.lu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.0x3d.lu/dist/",
+ "httpWebsiteMirror": "http://tor.0x3d.lu/",
+ "httpsDistMirror": "https://tor.0x3d.lu/dist/",
+ "httpsWebsiteMirror": "https://tor.0x3d.lu/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "0x3d.lu",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kraai(a)ftbfs.org 0xADCE6065",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ftbfs.org/dist/",
+ "httpWebsiteMirror": "http://tor.ftbfs.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "SE",
+ "loadBalanced": "No",
+ "orgName": "",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Sweden",
+ "updateDate\n": "Fri Oct 24 08:28:32 2014"
+ },
+ {
+ "adminContact": "kontakt(a)unicorncloud.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.unicorncloud.org/public/torproject.org/dist",
+ "httpWebsiteMirror": "http://www.unicorncloud.org/public/torproject.org/",
+ "httpsDistMirror": "https://www.unicorncloud.org/public/torproject.org/dist",
+ "httpsWebsiteMirror": "https://www.unicorncloud.org/public/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "UnicornCloud.org",
+ "region": "Wien",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Favoriten",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "James Murphy",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://108.248.87.242/dist/",
+ "httpWebsiteMirror": "http://108.248.87.242/",
+ "httpsDistMirror": "https://108.248.87.242/dist/",
+ "httpsWebsiteMirror": "https://108.248.87.242/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "intfxdx.com",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Sam Whited 4096R/54083AE104EA7AD3 <sam(a)samwhited.com>",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirrors.samwhited.net/tor/dist",
+ "httpWebsiteMirror": "http://mirrors.samwhited.net/tor",
+ "httpsDistMirror": "https://mirrors.samwhited.net/tor/dist",
+ "httpsWebsiteMirror": "https://mirrors.samwhited.net/tor",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "FALSE",
+ "orgName": "SamWhited.com",
+ "region": "United States",
+ "rsyncDistMirror": "rsync://mirrors.samwhited.net/tor-dist",
+ "rsyncWebsiteMirror": "rsync://mirrors.samwhited.net/tor",
+ "subRegion": "GA",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "rohit008 AT e DOT ntu DOT edu DOT sg",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ntuoss.com/dist/",
+ "httpWebsiteMirror": "http://torproject.ntuoss.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "SG",
+ "loadBalanced": "No",
+ "orgName": "NTUOSS",
+ "region": "Asia",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Singapore",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "jvictors at jessevictors dot com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-relay.cs.usu.edu/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://tor-relay.cs.usu.edu/mirrors/torproject.org/",
+ "httpsDistMirror": "https://www.jessevictors.com/secureMirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://www.jessevictors.com/secureMirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Department of CS at USU",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Jacob Henner",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ventricle.us/dist/",
+ "httpWebsiteMirror": "http://tor.ventricle.us/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "TRUE",
+ "orgName": "Anatomical Networks",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "hostmaster(a)lucidnetworks.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirrors.lucidnetworks.net/dist",
+ "httpWebsiteMirror": "http://tor.mirrors.lucidnetworks.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Lucid Networks",
+ "region": "US",
+ "rsyncDistMirror": "rsync://tor.mirrors.lucidnetworks.net::tor-dist",
+ "rsyncWebsiteMirror": "rsync://tor.mirrors.lucidnetworks.net::tor",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "hostmaster(a)vieth-server.de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirror-server.de/dist/",
+ "httpWebsiteMirror": "http://tor.mirror-server.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "mirror-server.de",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "mirror ntzk de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.ntzk.de/torproject.org/dist/",
+ "httpWebsiteMirror": "http://mirror.ntzk.de/torproject.org/",
+ "httpsDistMirror": "https://mirror.ntzk.de/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://mirror.ntzk.de/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Netzkonstrukt Berlin",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "mirror(a)xfree.com.ar",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.xfree.com.ar/dist/",
+ "httpWebsiteMirror": "http://tor.xfree.com.ar/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AR",
+ "loadBalanced": "No",
+ "orgName": "Xfree.com.ar",
+ "region": "South America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Argentina",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor AT eprci NET",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.eprci.net/dist/",
+ "httpWebsiteMirror": "http://tor.eprci.net/",
+ "httpsDistMirror": "https://www.eprci.com/tor/dist/",
+ "httpsWebsiteMirror": "https://www.eprci.com/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "EPRCI",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "NH",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)kura.io",
+ "ftpWebsiteMirror": "ftp://tor-mirror.kura.io",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.kura.io/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.kura.io/",
+ "httpsDistMirror": "https://tor-mirror.kura.io/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.kura.io/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NL",
+ "loadBalanced": "TRUE",
+ "orgName": "KURA IO LIMITED",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor-mirror.kura.io/torproject.org/dist",
+ "rsyncWebsiteMirror": "rsync://tor-mirror.kura.io/torproject.org",
+ "subRegion": "Netherlands",
+ "updateDate\n": "Thu Jan 22 16:27:59 2015"
+ },
+ {
+ "adminContact": "tor-admin AT wardsback DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://alliumcepa.wardsback.org/dist/",
+ "httpWebsiteMirror": "http://alliumcepa.wardsback.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "wardsback.org",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "PW",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.pw.is/dist/",
+ "httpWebsiteMirror": "http://tor.pw.is/",
+ "httpsDistMirror": "https://www.it-sicherheitschannel.de/dist/",
+ "httpsWebsiteMirror": "https://www.it-sicherheitschannel.de/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "PW",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kevin(a)freedom.press",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.freedom.press/dist/",
+ "httpWebsiteMirror": "http://tor.freedom.press",
+ "httpsDistMirror": "https://tor.freedom.press/dist/",
+ "httpsWebsiteMirror": "https://tor.freedom.press",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "",
+ "loadBalanced": "No",
+ "orgName": "Freedom of the Press Foundation",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "US",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "hsu AT peterdavehellor DOT org",
+ "ftpWebsiteMirror": "ftp://ftp.yzu.edu.tw/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://ftp.yzu.edu.tw/torproject.org/dist/",
+ "httpWebsiteMirror": "http://ftp.yzu.edu.tw/torproject.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "TW",
+ "loadBalanced": "No",
+ "orgName": "Department of CSE. Yuan Ze University",
+ "region": "Asia",
+ "rsyncDistMirror": "rsync://ftp.yzu.edu.tw/pub/torproject.org/dist/",
+ "rsyncWebsiteMirror": "rsync://ftp.yzu.edu.tw/pub/torproject.org/",
+ "subRegion": "Taiwan",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tormirror at sybec.net <mailto:tormirror at sybec.net>",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.sybec.net:8080/dist/ <http://tormirror.sybec.net:8080/dist/>",
+ "httpWebsiteMirror": "http://tormirror.sybec.net:8080/ <http://tormirror.sybec.net:8080/>",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "FALSE",
+ "orgName": "Sybec Services Ltd.",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "tor at tvdw dot eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-exit.network/dist",
+ "httpWebsiteMirror": "http://tor-exit.network",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "XX",
+ "loadBalanced": "Yes",
+ "orgName": "TvdW",
+ "region": "XX",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Around the world",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "spiderfly AT protonmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://onionphysics.com/dist/",
+ "httpWebsiteMirror": "http://onionphysics.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "ops at hoovism.com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://bt3ehg7prnlm6tyv.onion/",
+ "httpDistMirror": "http://tor.hoovism.com/dist/",
+ "httpWebsiteMirror": "http://tor.hoovism.com/",
+ "httpsDistMirror": "https://tor.hoovism.com/dist/",
+ "httpsWebsiteMirror": "https://tor.hoovism.com/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Matthew Hoover",
+ "region": "US",
+ "rsyncDistMirror": "rsync://tor.hoovism.com/tor/dist/",
+ "rsyncWebsiteMirror": "rsync://tor.hoovism.com/tor/",
+ "subRegion": "NJ",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tormaster AT urown DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://torprowdd64ytmyk.onion",
+ "httpDistMirror": "http://torproject.urown.net/dist/",
+ "httpWebsiteMirror": "http://torproject.urown.net/",
+ "httpsDistMirror": "https://torproject.urown.net/dist/",
+ "httpsWebsiteMirror": "https://torproject.urown.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "CH",
+ "loadBalanced": "No",
+ "orgName": "urown.net",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Switzerland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Stefan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://sela.io/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://sela.io/mirrors/torproject.org/",
+ "httpsDistMirror": "https://sela.io/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://sela.io/mirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "sela Internet",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "justaguy AT justaguy DOT pw",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://3qzbcsjhwseov7k4.onion",
+ "httpDistMirror": "http://services.justaguy.pw/dist",
+ "httpWebsiteMirror": "http://services.justaguy.pw/",
+ "httpsDistMirror": "https://services.justaguy.pw/dist",
+ "httpsWebsiteMirror": "https://services.justaguy.pw/",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Justaguy",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "thomaswhite AT riseup DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.thecthulhu.com/dist/",
+ "httpWebsiteMirror": "http://tor.thecthulhu.com/",
+ "httpsDistMirror": "https://tor.thecthulhu.com/dist/",
+ "httpsWebsiteMirror": "https://tor.thecthulhu.com/",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "TheCthulhu",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "rush23 AT gmx DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-proxy.euve59946.serverprofi24.de/dist/",
+ "httpWebsiteMirror": "http://tor-proxy.euve59946.serverprofi24.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Thu Jun 4 19:06:42 2015"
+ },
+ {
+ "adminContact": "webmaster AT ccc DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ccc.de/dist/",
+ "httpWebsiteMirror": "http://tor.ccc.de/",
+ "httpsDistMirror": "https://tor.ccc.de/dist/",
+ "httpsWebsiteMirror": "https://tor.ccc.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "CCC",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "mitchell AT lcsks DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "http://mirror.lcsks.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "CCC",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ }
+]
\ No newline at end of file
diff --git a/tor-mirrors.csv b/tor-mirrors.csv
new file mode 100644
index 0000000..5ca8f03
--- /dev/null
+++ b/tor-mirrors.csv
@@ -0,0 +1,116 @@
+adminContact, orgName, isoCC, subRegion, region, ipv4, ipv6, loadBalanced, httpWebsiteMirror, httpsWebsiteMirror, rsyncWebsiteMirror, ftpWebsiteMirror, httpDistMirror, httpsDistMirror, rsyncDistMirror, hiddenServiceMirror, updateDate
+Tor Fan, Tor Supporter, US, United States, US, TRUE, TRUE, No, http://tor.loritsu.com/, , , , http://tor.loritsu.com/dist/, , , ,
+Tor Fan, Tor Supporter, LU, Luxemborg, LU, TRUE, FALSE, No, http://torproject.adamas.ai/, , , , http://torproject.adamas.ai/dist/, , , ,
+Tor Fan, Tor Supporter, UA, Ukraine, UA, TRUE, FALSE, No, http://torua.reactor-xg.kiev.ua/, , , , http://torua.reactor-xg.kiev.ua/dist/, , , ,
+Tor Fan, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://37.187.0.127/tormirror/, , , , http://37.187.0.127/tormirror/dist/, , , ,
+Tor Fan, Tor Supporter, US, United States, US, TRUE, FALSE, No, http://tor.minibofh.org/, , , , http://tor.minibofh.org/dist/, , , ,
+Tor Fan, Tor Supporter, UK, United Kingdom, UK, TRUE, FALSE, No, http://tor.mage.me.uk/, , , , http://tor.mage.me.uk/dist/, , , ,
+nsane2307 eml cc, tor-mirror.de, DE, Germany, Europe, TRUE, FALSE, No, http://tor-mirror.de/, https://tor-mirror.de/, , , http://tor-mirror.de/dist/, https://tor-mirror.de/dist/, , ,
+citizen428 AT gmail DOT com, [[:bbs:]], DE, Germany, Europe, TRUE, FALSE, No, http://tor.blingblingsquad.net/, https://tor.blingblingsquad.net/, , , http://tor.blingblingsquad.net/dist/, https://tor.blingblingsquad.net/dist/, , ,
+Tor Fan, NW Linux, US, WA, US, TRUE, FALSE, No, http://torproject.nwlinux.us/, , rsync://nwlinux.us/tor-web, , http://torproject.nwlinux.us/dist/, , rsync://nwlinux.us/tor-dist, ,
+Tor Fan, Tor Supporter, NL, The Netherlands, NL, TRUE, FALSE, No, , , , , , https://www.coevoet.nl/tor/dist/, , ,
+Tor Fan, LazyTiger, FR, France, FR, TRUE, FALSE, No, http://tor.taiga-san.net/, , , , http://tor.taiga-san.net/dist/, , , ,
+Tor Fan, Tor Supporter, EE, Estonia, EE, TRUE, FALSE, No, http://tor.li/, https://tor.li/, , , http://tor.li/dist/, https://tor.li/dist/, , ,
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, FALSE, NO, http://tor.externenprüfung-nichtschüler.de/, , , , http://tor.externenprüfung-nichtschüler.de/dist/, , , ,
+mirror-service(a)netcologne.de, NetCologne GmbH, DE, NRW, , TRUE, TRUE, No, http://mirror.netcologne.de/torproject.org, , rsync://mirror.netcologne.de/torproject.org, ftp://mirror.netcologne.de/torproject.org/, http://mirror.netcologne.de/torproject.org/dist, , rsync://mirror.netcologne.de/torproject.org/dist, , Wed Jul 15 18:49:12 2015
+admin AT netgull DOT com, NetGull, US, United States, North America, TRUE, TRUE, No, , , , , http://www.netgull.com/torproject/, , , ,
+mirrors[at]ip-connect[dot]vn[dot]ua, IP-Connect LLC, UA, VN, , TRUE, TRUE, Yes, http://torproject.ip-connect.vn.ua, , rsync://torproject.ip-connect.vn.ua/torproject, ftp://torproject.ip-connect.vn.ua/mirror/torproject/, http://torproject.ip-connect.vn.ua/dist, , rsync://torproject.ip-connect.vn.ua/torproject/dist, , Wed Jul 15 18:49:12 2015
+torsupport AT tb-itf DOT de, TB-ITF, DE, Germany, Europe, TRUE, TRUE, No, http://tormirror.tb-itf-tor.de, https://tormirror.tb-itf-tor.de, , , http://tormirror.tb-itf-tor.de/dist/, https://tormirror.tb-itf-tor.de/dist/, , , Wed Jul 15 18:49:12 2015
+admin at koreswatanabe dottnet, Tor Supporter, RO, Romania, RO, TRUE, TRUE, No, http://tor-relay.koreswatanabe.net, , , , http://tor-relay.koreswatanabe.net/dist/, , , ,
+calebcenter(a)live.com, calebxu.tk, US, United States, US, TRUE, FALSE, NO, http://tor.calebxu.tk, , rsync://calebxu.tk/tor, ftp://ftp.calebxu.tk, http://tor.calebxu.tk/dist, , , ,
+maki(a)maki-chan.de, Maki Hoshisawa, DE, Germany, DE, TRUE, FALSE, NO, http://tor.mirrors.maki-chan.de/, , , , http://tor.mirrors.maki-chan.de/dist/, , , , Sat Aug 23 08:09:07 2014
+info AT zentrum-der-gesundheit DOT de, Zentrum der Gesundheit, DK, Denmark, Europe, TRUE, FALSE, No, http://tor.idnr.ws/, , , , http://tor.idnr.ws/dist/, , , , Tue Sep 2 11:16:00 2014
+info /AT enn /DOT lu, Frenn vun der Enn A.S.B.L., IS, Iceland, Europe, TRUE, FALSE, No, http://torproject.lu/, , , , http://torproject.lu/dist/, , , http://btn6gqzqevlhoryd.onion, Wed Jul 15 18:49:12 2015
+Piratenpartei Bayern, Piratenpartei Bayern, DE, Germany, DE, TRUE, FALSE, NO, http://tormirror.piratenpartei-bayern.de, https://tormirror.piratenpartei-bayern.de, , , http://tormirror.piratenpartei-bayern.de/dist/, https://tormirror.piratenpartei-bayern.de/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, TRUE, NO, http://tor.hoi-polloi.org, https://tor.hoi-polloi.org/, , , http://tor.hoi-polloi.org/dist/, https://tor.hoi-polloi.org/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)fodt.it // FoDT.it Webteam, FoDT.it, AT, Austria, Europe, TRUE, FALSE, No, http://tor.fodt.it, https://tor.fodt.it, , ftp://ftp.fodt.it/pub/mirrors/torproject.org/, http://tor.fodt.it/dist/, https://tor.fodt.it/dist/, , , Mon Aug 25 10:19:07 2014
+http://www.multinet.no, MultiNet AS, NO, Trondheim, Trondheim, TRUE, TRUE, No, http://tor.multinet.no/, , , , http://tor.multinet.no/dist/, , , , Wed Jul 15 18:49:12 2015
+haskell at gmx.es, Tor Supporter, ES, Spain, Europe, TRUE, TRUE, No, http://tor.zilog.es/, https://tor.zilog.es/, , , http://tor.zilog.es/dist/, https://tor.zilog.es/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, US, United States, US, TRUE, FALSE, No, http://199.175.55.215/, https://199.175.55.215/, , , http://199.175.55.215/dist/, https://199.175.55.215/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, US, United States, US, FALSE, TRUE, No, http://2607:8b00:2::6258:5c9/, https://2607:8b00:2::6258:5c9/, , , http://2607:8b00:2::6258:5c9/dist/, https://2607:8b00:2::6258:5c9/dist/, , , Tue Jan 20 16:17:52 2015
+margus.random at mail.ee, CyberSIDE, EE, Estonia, EE, TRUE, FALSE, No, http://cyberside.planet.ee/tor/, , , , http://cyberside.net.ee/tor/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, torproject.is, IS, Iceland, IS, TRUE, FALSE, No, http://www.torproject.is/, , , , http://www.torproject.is/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, spline, DE, Germany, DE, TRUE, FALSE, No, http://tor.spline.de/, https://tor.spline.inf.fu-berlin.de/, rsync://ftp.spline.de/tor, ftp://ftp.spline.de/pub/tor, http://tor.spline.de/dist/, https://tor.spline.inf.fu-berlin.de/dist/, rsync://ftp.spline.de/tor/dist, , Wed Jul 15 18:49:12 2015
+Tor Fan, me0w.cc, RO, Romania, RO, TRUE, FALSE, No, http://tor.me0w.cc/, , , , http://tor.me0w.cc/dist/, , , , Thu Jan 1 16:17:56 2015
+Tor Fan, borgmann.tv, DE, Germany, DE, TRUE, FALSE, No, http://tor.borgmann.tv/, , , , http://tor.borgmann.tv/dist/, , , , Sun Jul 12 19:04:44 2015
+Tor Fan, Tor Supporter, AT, Austria, AT, TRUE, TRUE, No, http://tor.dont-know-me.at/, , , , http://tor.dont-know-me.at/dist/, , , , Tue Jan 20 16:17:52 2015
+coralcdn.org, CoralCDN, INT, International, INT, TRUE, FALSE, Yes, http://www.torproject.org.nyud.net/, , , , http://www.torproject.org.nyud.net/dist/, , , , Thu Jan 8 02:01:06 2015
+Tor Fan, Tor Supporter, AT, Austria, AT, TRUE, FALSE, No, http://torproject.ph3x.at/, , , , http://torproject.ph3x.at/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, MX, Mexico, MX, TRUE, FALSE, No, http://fbnaia.homelinux.net/torproject/, https://fbnaia.homelinux.net/torproject/, , , http://fbnaia.homelinux.net/torproject/dist/, https://fbnaia.homelinux.net/torproject/dist/, , , Wed Jul 15 18:49:12 2015
+webmaster AT askapache DOT com, AskApache, US, California, US, TRUE, FALSE, No, http://tor.askapache.com/, , , , http://tor.askapache.com/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://tor.mirror.chekanov.net/, , , , http://tor.mirror.chekanov.net/dist/, , , , Mon Mar 16 15:53:03 2015
+kontakt AT unicorncloud DOT org, UnicornCloud.org, DE, Germany, Falkenstein, TRUE, FALSE, No, http://mirror.unicorncloud.org/torproject.org/, https://mirror.unicorncloud.org/torproject.org/, , , http://mirror.unicorncloud.org/torproject.org/dist, https://mirror.unicorncloud.org/torproject.org/dist, , , Wed Jul 15 18:49:12 2015
+root AT amorphis DOT eu, Amorphis, NL, The Netherlands, Europe, TRUE, FALSE, No, http://tor.amorphis.eu/, , , , http://tor.amorphis.eu/dist/, , , , Mon Mar 16 15:53:03 2015
+hackthissite.org, HackThisSite.org, US, United States, US, TRUE, TRUE, No, http://tor.hackthissite.org/, https://tor.hackthissite.org/, , , http://mirror.hackthissite.org/tor, https://mirror.hackthissite.org/tor, , , Wed Jul 15 18:49:12 2015
+paul at coffswifi.net, CoffsWiFi, AU, Australia and New Zealand, APNIC, TRUE, FALSE, No, http://torproject.coffswifi.net, , , , http://torproject.coffswifi.net/dist, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, cyberarmy, AT, Austria, AT, TRUE, FALSE, No, http://tor.cyberarmy.at/, , , , , , , , Wed Jul 15 18:49:12 2015
+hostmaster AT example DOT com, TheOnionRouter, IS, Iceland, Iceland, TRUE, FALSE, No, http://www.theonionrouter.com/, , , , http://www.theonionrouter.com/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, crazyhaze.de, DE, Germany, DE, TRUE, FALSE, No, http://tor.crazyhaze.de/, https://tor.crazyhaze.de/, , , http://tor.crazyhaze.de/dist/, https://tor.crazyhaze.de/dist/, , , Tue Jul 7 13:16:29 2015
+Tor Fan, chaos darmstadt, DE, Germany, Europe, TRUE, FALSE, No, http://mirrors.chaos-darmstadt.de/tor-mirror/, , , , http://mirrors.chaos-darmstadt.de/tor-mirror/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Soviet Anonymous, RU, Russia, RU, TRUE, FALSE, No, http://creep.im/tor, https://creep.im/tor, rsync://creep.im/tor, ftp://creep.im/mirrors/tor, http://creep.im/tor/dist/, https://creep.im/tor/dist/, rsync://creep.im/tor-dist, , Wed Jul 15 18:49:12 2015
+Tor Fan, torservers, DE, Germany, DE, TRUE, FALSE, No, http://www.torservers.net/mirrors/torproject.org/, https://www.torservers.net/mirrors/torproject.org/, , , http://www.torservers.net/mirrors/torproject.org/dist/, https://www.torservers.net/mirrors/torproject.org/dist/, , http://hbpvnydyyjbmhx6b.onion/mirrors/torproject.org/, Wed Jul 15 18:49:12 2015
+Tor Fan, torland, GB, United Kingdom, GB, TRUE, FALSE, No, http://mirror.torland.me/torproject.org/, https://mirror.torland.me/torproject.org/, , , http://mirror.torland.me/torproject.org/dist/, https://mirror.torland.me/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Lightning-bolt.net, CZ, Czech Republic, CZ, TRUE, FALSE, No, http://torproject.lightning-bolt.net/, , , , http://torproject.lightning-bolt.net/dist/, , , , Mon Mar 16 15:53:03 2015
+IceBear, myRL.net, IS, Iceland, IS, TRUE, FALSE, No, http://tor.myrl.net/, https://tor.myrl.net/, , , http://tor.myrl.net/dist/, https://tor.myrl.net/dist/, , , Wed Jul 15 18:49:12 2015
+kiro AT userzap DOT de, Userzap, DE, Germany, DE, TRUE, FALSE, No, http://torprojekt.userzap.de, https://torprojekt.userzap.de, , , http://torprojekt.userzap.de/dist/, https://torprojekt.userzap.de/dist/, , , Tue Jan 20 16:17:52 2015
+tor(a)les.net, tor(a)les.net, CA, Canada, CA, TRUE, FALSE, NO, http://tor.les.net/, , , , http://tor.les.net/dist, , , , Wed Jul 15 18:49:12 2015
+tor(a)stalkr.net, stalkr.net, FR, France, FR, TRUE, TRUE, NO, http://tor.stalkr.net/, https://tor.stalkr.net/, , , http://tor.stalkr.net/dist/, https://tor.stalkr.net/dist/, , , Wed Jul 15 18:49:12 2015
+doemela[AT]cyberguerrilla[DOT]org, cYbergueRrilLa AnonyMous NeXus, DE, Germany, DE, TRUE, FALSE, NO, , https://tor-mirror.cyberguerrilla.org, , , , https://tor-mirror.cyberguerrilla.org/dist/, , http://6dvj6v5imhny3anf.onion, Wed Jul 15 18:49:12 2015
+contact(a)gtor.org, Gtor, DE, Germany, DE, TRUE, TRUE, NO, http://torproject.gtor.org/, https://torproject.gtor.org/, rsync://torproject.gtor.org/website-mirror/, , http://torproject.gtor.org/dist/, https://torproject.gtor.org/dist/, rsync://torproject.gtor.org/website-mirror/dist/, , Wed Jul 15 18:49:12 2015
+SDL, SDL, US, United States, US, TRUE, TRUE, NO, http://torproject.nexiom.net, https://torproject.nexiom.net, , , http://torproject.nexiom.net, https://torproject.nexiom.net/dist, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, TRUE, NO, http://mirror.velcommuta.de/tor/, https://mirror.velcommuta.de/tor/, , , http://mirror.velcommuta.de/tor/dist/, https://mirror.velcommuta.de/tor/dist/, , , Wed Jul 15 18:49:12 2015
+EFF, EFF, US, United States, US, TRUE, FALSE, NO, , https://tor.eff.org, , , , https://tor.eff.org/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, GR, Greece, GR, TRUE, TRUE, NO, http://tor.void.gr, https://tor.void.gr, , , http://tor.void.gr/dist/, https://tor.void.gr/dist/, , , Wed Jul 15 18:49:12 2015
+Ich Eben, Tor Supporter, DE, Germany, DE, TRUE, TRUE, No, http://reichster.de/mirrors/torproject.org/, https://reichster.de/mirrors/torproject.org, , , http://reichster.de/mirrors/torproject.org/dist/, https://reichster.de/mirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+jlgaddis AT gnu DOT org, Evil Routers, US, United States, US, TRUE, FALSE, No, http://tor1.evilrouters.net/, , , , http://tor1.evilrouters.net/dist/, , , , Wed Jul 15 18:49:12 2015
+tor AT miglix DOT eu, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, NO, http://tor.miglix.eu, https://tor.miglix.eu, , , http://tor.miglix.eu/dist/, https://tor.miglix.eu/dist/, , , Wed Jul 15 18:49:12 2015
+tor TA ninurta TOD name, TorNinurtaName, AT, Austria, AT, TRUE, TRUE, no, http://tor.ninurta.name/, , , , http://tor.ninurta.name/dist/, , , , Wed Oct 22 15:02:17 2014
+fr33tux <AT> general-changelog-team.fr, Tor Supporter, FR, France, FR, TRUE, TRUE, No, http://tor.fr33tux.org, https://tor.fr33tux.org, , , http://tor.fr33tux.org/dist/, https://tor.fr33tux.org/dist/, , , Wed Jul 15 18:49:12 2015
+sebastian(at)bobrecki(dot)pl, Sebastian M. Bobrecki, PL, Poland, Europe, TRUE, FALSE, No, http://tor.iv.net.pl, https://tor.iv.net.pl, , , http://tor.iv.net.pl/dist/, https://tor.iv.net.pl/dist/, , , Wed Jul 15 18:49:12 2015
+tor-mirror AT rdns DOT cc, d0wn.biz, FR, France, Europe, TRUE, FALSE, No, http://tor.static.lu, https://tor.static.lu, , , http://tor.static.lu/dist/, https://tor.static.lu/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)moparisthebest.com, moparisthebest.com, DE, Germany, Europe, TRUE, TRUE, No, http://www.moparisthebest.com/tor/, https://www.moparisthebest.com/tor/, , , http://www.moparisthebest.com/tor/dist/, https://www.moparisthebest.com/tor/dist/, , , Wed Jul 15 18:49:12 2015
+Sebastian, Maxanoo, NL, The Netherlands, Amsterdam, TRUE, FALSE, NO, http://tor.maxanoo.com/, , , , http://tor.maxanoo.com/dist/, , , , Sun May 31 15:13:53 2015
+rorrim AT ayo DOT tl, Tor Supporter, IS, Iceland, Europe, TRUE, TRUE, No, http://ayo.tl/tor/, https://ayo.tl/tor/, , , http://ayo.tl/tor/dist/, https://ayo.tl/tor/dist/, , , Tue Jan 20 16:17:52 2015
+stefano.fenoglio AT gmail DOT com, Tor Supporter, IT, Italy, Europe, TRUE, FALSE, No, http://tor.stefanof.com, , , , http://tor.stefanof.com/dist, , , , Sun Jul 12 13:19:35 2015
+Tor Fan, Ramos Research, US, United States, US, TRUE, TRUE, No, http://tor.ramosresearch.com/, , , , http://tor.ramosresearch.com/dist/, , , , Mon Mar 16 15:53:03 2015
+Tor Fan, Tor Supporter, DE, Germany, Europe, TRUE, FALSE, No, http://tor.euve33747.vserver.de/, , , , http://tor.euve33747.vserver.de/dist, , , , Wed Jul 15 18:49:12 2015
+s7r[at]sky-ip[d0t]org, sky-ip.org, NL, Netherlands, NL, TRUE, FALSE, No, http://beautiful-mind.sky-ip.org/, , , , http://beautiful-mind.sky-ip.org/dist/, , , , Wed Jul 15 18:49:12 2015
+tor#pajonzeck#de, ITsn, DE, Germany, Europe, TRUE, FALSE, No, http://tor.pajonzeck.de/, https://tor.pajonzeck.de/, rsync://tor.pajonzeck.de/tor, , http://tor.pajonzeck.de/dist/, https://tor.pajonzeck.de/dist/, rsync://tor.pajonzeck.de/tor/dist, http://zgfgvob256pffy62.onion, Wed Jul 15 18:49:12 2015
+peter AT ludikovsky DOT name, Tor Supporter, AT, Austria, Europe, TRUE, TRUE, No, http://tor.ludikovsky.name/, https://tor.ludikovsky.name/, rsync://tor.ludikovsky.name/tor, , http://tor.ludikovsky.name/dist, https://tor.ludikovsky.name/dist, rsync://tor.ludikovsky.name/tor-dist, http://54lnbzjo6xlr4f4j.onion/, Wed Jul 15 18:49:12 2015
+admin AT nuclear DASH weapons DOT net, Setec Administrator, US, Texas, Austin, TRUE, FALSE, No, http://tor.nuclear-weapons.net, https://tor.nuclear-weapons.net, , , http://tor.nuclear-weapons.net/dist, https://tor.nuclear-weapons.net/dist, , , Wed Jul 15 18:49:12 2015
+0x43DE8191, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, No, http://torproject.hactar.bz, , , , http://torproject.hactar.bz/dist/, , , , Wed Jul 15 18:49:12 2015
+-nick at calyx dot com, The Calyx Institute, US, United States, North America, TRUE, FALSE, No, http://tor.calyxinstitute.org, https://tor.calyxinstitute.org, , , http://tor.calyxinstitute.org/dist/, https://tor.calyxinstitute.org/dist/, , http://tmdrhl4e4anhsjc5.onion, Wed Jul 15 18:49:12 2015
+opi(a)zeropi.net, Tor Supporter, FR, France, FR, TRUE, TRUE, No, http://tor-mirror.zeropi.net/, , , , http://tor-mirror.zeropi.net/dist/, , , , Mon Dec 1 12:15:20 2014
+noc AT babylon DOT network, Babylon Network, NL, The Netherlands, Europe, TRUE, TRUE, No, http://mirror2.babylon.network/torproject/, https://mirror2.babylon.network/torproject/, rsync://mirror2.babylon.network/torproject/, ftp://mirror2.babylon.network/torproject/, http://mirror2.babylon.network/torproject/dist/, https://mirror2.babylon.network/torproject/dist/, rsync://mirror2.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+noc AT babylon DOT network, Babylon Network, FR, France, Europe, TRUE, TRUE, No, http://mirror0.babylon.network/torproject/, https://mirror0.babylon.network/torproject/, rsync://mirror0.babylon.network/torproject/, ftp://mirror0.babylon.network/torproject/, http://mirror0.babylon.network/torproject/dist/, https://mirror0.babylon.network/torproject/dist/, rsync://mirror0.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+noc AT babylon DOT network, Babylon Network, FR, France, Europe, TRUE, TRUE, No, http://mirror1.babylon.network/torproject/, https://mirror1.babylon.network/torproject/, rsync://mirror1.babylon.network/torproject/, ftp://mirror1.babylon.network/torproject/, http://mirror1.babylon.network/torproject/dist/, https://mirror1.babylon.network/torproject/dist/, rsync://mirror1.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+alexander AT dietrich DOT cx, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, No, http://tor.ybti.net/, https://tor.ybti.net/, , , http://tor.ybti.net/dist/, https://tor.ybti.net/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)0x3d.lu, 0x3d.lu, DE, Germany, Europe, TRUE, FALSE, No, http://tor.0x3d.lu/, https://tor.0x3d.lu/, , , http://tor.0x3d.lu/dist/, https://tor.0x3d.lu/dist/, , , Wed Jul 15 18:49:12 2015
+kraai(a)ftbfs.org 0xADCE6065, , SE, Sweden, Europe, TRUE, TRUE, No, http://tor.ftbfs.org/, , , , http://tor.ftbfs.org/dist/, , , , Fri Oct 24 08:28:32 2014
+kontakt(a)unicorncloud.org, UnicornCloud.org, AT, Favoriten, Wien, TRUE, TRUE, No, http://www.unicorncloud.org/public/torproject.org/, https://www.unicorncloud.org/public/torproject.org/, , , http://www.unicorncloud.org/public/torproject.org/dist, https://www.unicorncloud.org/public/torproject.org/dist, , , Mon Mar 16 15:53:03 2015
+James Murphy, intfxdx.com, US, United States, US, TRUE, TRUE, No, http://108.248.87.242/, https://108.248.87.242/, , , http://108.248.87.242/dist/, https://108.248.87.242/dist/, , , Wed Jul 15 18:49:12 2015
+Sam Whited 4096R/54083AE104EA7AD3 <sam(a)samwhited.com>, SamWhited.com, US, GA, United States, TRUE, TRUE, FALSE, http://mirrors.samwhited.net/tor, https://mirrors.samwhited.net/tor, rsync://mirrors.samwhited.net/tor, , http://mirrors.samwhited.net/tor/dist, https://mirrors.samwhited.net/tor/dist, rsync://mirrors.samwhited.net/tor-dist, , Wed Jul 15 18:49:12 2015
+rohit008 AT e DOT ntu DOT edu DOT sg, NTUOSS, SG, Singapore, Asia, TRUE, FALSE, No, http://torproject.ntuoss.com/, , , , http://torproject.ntuoss.com/dist/, , , , Mon Mar 16 15:53:03 2015
+jvictors at jessevictors dot com, Department of CS at USU, US, United States, North America, TRUE, FALSE, No, http://tor-relay.cs.usu.edu/mirrors/torproject.org/, https://www.jessevictors.com/secureMirrors/torproject.org/, , , http://tor-relay.cs.usu.edu/mirrors/torproject.org/dist/, https://www.jessevictors.com/secureMirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+Jacob Henner, Anatomical Networks, US, United States, US, TRUE, TRUE, TRUE, http://tor.ventricle.us/, , , , http://tor.ventricle.us/dist/, , , , Tue Jan 20 16:17:52 2015
+hostmaster(a)lucidnetworks.net, Lucid Networks, US, United States, US, TRUE, FALSE, No, http://tor.mirrors.lucidnetworks.net, , rsync://tor.mirrors.lucidnetworks.net::tor, , http://tor.mirrors.lucidnetworks.net/dist, , rsync://tor.mirrors.lucidnetworks.net::tor-dist, , Wed Jul 15 18:49:12 2015
+hostmaster(a)vieth-server.de, mirror-server.de, DE, Germany, DE, TRUE, TRUE, No, http://tor.mirror-server.de/, , , , http://tor.mirror-server.de/dist/, , , , Tue Jan 20 16:17:52 2015
+mirror ntzk de, Netzkonstrukt Berlin, DE, Germany, Europe, TRUE, FALSE, No, http://mirror.ntzk.de/torproject.org/, https://mirror.ntzk.de/torproject.org/, , , http://mirror.ntzk.de/torproject.org/dist/, https://mirror.ntzk.de/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+mirror(a)xfree.com.ar, Xfree.com.ar, AR, Argentina, South America, TRUE, FALSE, No, http://tor.xfree.com.ar/, , , , http://tor.xfree.com.ar/dist/, , , , Wed Jul 15 18:49:12 2015
+tor AT eprci NET, EPRCI, US, NH, US, TRUE, FALSE, No, http://tor.eprci.net/, https://www.eprci.com/tor/, , , http://tor.eprci.net/dist/, https://www.eprci.com/tor/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)kura.io, KURA IO LIMITED, NL, Netherlands, Europe, TRUE, TRUE, TRUE, http://tor-mirror.kura.io/, https://tor-mirror.kura.io/, rsync://tor-mirror.kura.io/torproject.org, ftp://tor-mirror.kura.io, http://tor-mirror.kura.io/dist/, https://tor-mirror.kura.io/dist/, rsync://tor-mirror.kura.io/torproject.org/dist, , Thu Jan 22 16:27:59 2015
+tor-admin AT wardsback DOT org, wardsback.org, FR, France, FR, TRUE, FALSE, No, http://alliumcepa.wardsback.org/, , , , http://alliumcepa.wardsback.org/dist/, , , , Wed Jul 15 18:49:12 2015
+PW, PW, DE, Germany, DE, TRUE, TRUE, NO, http://tor.pw.is/, https://www.it-sicherheitschannel.de/, , , http://tor.pw.is/dist/, https://www.it-sicherheitschannel.de/dist/, , , Wed Jul 15 18:49:12 2015
+kevin(a)freedom.press, Freedom of the Press Foundation, , US, US, True, False, No, http://tor.freedom.press, https://tor.freedom.press, , , http://tor.freedom.press/dist/, https://tor.freedom.press/dist/, , ,
+hsu AT peterdavehellor DOT org, Department of CSE. Yuan Ze University, TW, Taiwan, Asia, TRUE, FALSE, No, http://ftp.yzu.edu.tw/torproject.org/, , rsync://ftp.yzu.edu.tw/pub/torproject.org/, ftp://ftp.yzu.edu.tw/torproject.org/, http://ftp.yzu.edu.tw/torproject.org/dist/, , rsync://ftp.yzu.edu.tw/pub/torproject.org/dist/, , Wed Jul 15 18:49:12 2015
+tormirror at sybec.net <mailto:tormirror at sybec.net>, Sybec Services Ltd., DE, Germany, DE, TRUE, FALSE, FALSE, http://tormirror.sybec.net:8080/ <http://tormirror.sybec.net:8080/>, , , , http://tormirror.sybec.net:8080/dist/ <http://tormirror.sybec.net:8080/dist/>, , , ,
+tor at tvdw dot eu, TvdW, XX, Around the world, XX, TRUE, TRUE, Yes, http://tor-exit.network, , , , http://tor-exit.network/dist, , , , Wed Jul 15 18:49:12 2015
+spiderfly AT protonmail DOT com, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://onionphysics.com, , , , http://onionphysics.com/dist/, , , , Wed Jul 15 18:49:12 2015
+ops at hoovism.com, Matthew Hoover, US, NJ, US, TRUE, TRUE, No, http://tor.hoovism.com/, https://tor.hoovism.com/, rsync://tor.hoovism.com/tor/, , http://tor.hoovism.com/dist/, https://tor.hoovism.com/dist/, rsync://tor.hoovism.com/tor/dist/, http://bt3ehg7prnlm6tyv.onion/, Wed Jul 15 18:49:12 2015
+tormaster AT urown DOT net, urown.net, CH, Switzerland, Europe, TRUE, TRUE, No, http://torproject.urown.net/, https://torproject.urown.net/, , , http://torproject.urown.net/dist/, https://torproject.urown.net/dist/, , http://torprowdd64ytmyk.onion, Wed Jul 15 18:49:12 2015
+Stefan, sela Internet, DE, Germany, DE, TRUE, TRUE, No, http://sela.io/mirrors/torproject.org/, https://sela.io/mirrors/torproject.org/, , , http://sela.io/mirrors/torproject.org/dist/, https://sela.io/mirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+justaguy AT justaguy DOT pw, Justaguy, NL, The Netherlands, NL, True, False, No, http://services.justaguy.pw/, https://services.justaguy.pw/, , , http://services.justaguy.pw/dist, https://services.justaguy.pw/dist, , http://3qzbcsjhwseov7k4.onion, Wed Jul 15 18:49:12 2015
+thomaswhite AT riseup DOT net, TheCthulhu, NL, The Netherlands, NL, True, False, No, http://tor.thecthulhu.com/, https://tor.thecthulhu.com/, , , http://tor.thecthulhu.com/dist/, https://tor.thecthulhu.com/dist/, , , Wed Jul 15 18:49:12 2015
+rush23 AT gmx DOT net, Tor Supporter, DE, Germany, Europe, TRUE, FALSE, No, http://tor-proxy.euve59946.serverprofi24.de/, , , , http://tor-proxy.euve59946.serverprofi24.de/dist/, , , , Thu Jun 4 19:06:42 2015
+webmaster AT ccc DOT de, CCC, NL, The Netherlands, Europe, TRUE, FALSE, No, http://tor.ccc.de/, https://tor.ccc.de, , , http://tor.ccc.de/dist/, https://tor.ccc.de/dist/, , , Wed Jul 15 18:49:12 2015
+mitchell AT lcsks DOT com, CCC, US, United States, US, TRUE, FALSE, No, http://mirror.lcsks.com, , , , , , , ,
1
0
commit e35c09f55571c1b1966c263643a38eaeb94c8a9a
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:08:29 2015 -0300
Debugging improvements
---
process_email.py | 41 +++++++++++++++++++++++++++++++++++++++++
smtp_demo.py | 22 ----------------------
2 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/process_email.py b/process_email.py
new file mode 100644
index 0000000..504b5dd
--- /dev/null
+++ b/process_email.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+import logging
+
+import gettor.smtp
+
+def main():
+ logging_level = 'INFO'
+ logging_file = '/path/to/gettor/log/process_email.log'
+ logging_format = '[%(levelname)s] %(asctime)s - %(message)s'
+ date_format = "%Y-%m-%d" # %H:%M:%S
+
+ logging.basicConfig(
+ format=logging_format,
+ datefmt=date_format,
+ filename = logging_file,
+ level = logging_level
+ )
+
+ logging.debug("New email received")
+ logging.debug("Creating new SMTP object")
+
+ try:
+ service = gettor.smtp.SMTP('/path/to/gettor/smtp.cfg')
+ incoming = sys.stdin.read()
+ service.process_email(incoming)
+ logging.debug("Email processed sucessfully")
+ except gettor.smtp.ConfigError as e:
+ logging.error("Configuration error: %s" % str(e))
+ except gettor.smtp.SendEmailError as e:
+ logging.error("SMTP not working: %s" % str(e))
+ except gettor.smtp.InternalError as e:
+ logging.error("Core module not working: %s" % str(e))
+ except Exception as e:
+ # in case something unexpected happens
+ logging.critical("Unexpected error: %s" % str(e))
+
+if __name__ == '__main__':
+ main()
diff --git a/smtp_demo.py b/smtp_demo.py
deleted file mode 100644
index 0ec341e..0000000
--- a/smtp_demo.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-import sys
-
-import gettor.smtp
-
-service = gettor.smtp.SMTP()
-
-# For now we simulate mails reading from stdin
-# In linux test as follows:
-# $ python smtp_demo.py < email.eml
-
-incoming = sys.stdin.read()
-try:
- print "Email received!"
- service.process_email(incoming)
- print "Email sent!"
-except gettor.smtp.ConfigError as e:
- print "Misconfiguration: " + str(e)
-except gettor.smtp.SendEmailError as e:
- print "SMTP not working: " + str(e)
-except gettor.smtp.InternalError as e:
- print "Core module not working: " + str(e)
1
0
commit c745cbd07d09b368b058b208a51c5ae66e8aa736
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:16:08 2015 -0300
Better format for sending the links
---
gettor/core.py | 86 +++++++++++++++++++++++++++++++----
gettor/smtp.py | 19 +++++---
lang/core/i18n/en/en.po | 2 +-
lang/smtp/i18n/en/LC_MESSAGES/en.po | 4 +-
4 files changed, 94 insertions(+), 17 deletions(-)
diff --git a/gettor/core.py b/gettor/core.py
index 219fed2..49fbbb2 100644
--- a/gettor/core.py
+++ b/gettor/core.py
@@ -197,7 +197,18 @@ class Core(object):
# read the links files using ConfigParser
# see the README for more details on the format used
- links = []
+ links_files = []
+
+ links32 = {}
+ links64 = {}
+
+ # for the message to be sent
+ if osys == 'windows':
+ arch = '32/64'
+ elif osys == 'osx':
+ arch = '64'
+ else:
+ arch = '32'
# look for files ending with .links
p = re.compile('.*\.links$')
@@ -205,7 +216,7 @@ class Core(object):
for name in os.listdir(self.linksdir):
path = os.path.abspath(os.path.join(self.linksdir, name))
if os.path.isfile(path) and p.match(path):
- links.append(path)
+ links_files.append(path)
# let's create a dictionary linking each provider with the links
# found for os and lc. This way makes it easy to check if no
@@ -216,7 +227,7 @@ class Core(object):
spt = '=' * 72
# reading links from providers directory
- for name in links:
+ for name in links_files:
# we're reading files listed on linksdir, so they must exist!
config = ConfigParser.ConfigParser()
# but just in case they don't
@@ -231,14 +242,34 @@ class Core(object):
# check if current provider pname has links for os in lc
providers[pname] = config.get(osys, lc)
- # avoid showing it all together
- providers[pname] = providers[pname].replace(",", "")
- providers[pname] = providers[pname].replace("$", "\n\n")
+ except ConfigParser.Error as e:
+ # we should at least have the english locale available
+ self.log.error("Request for %s, returning 'en' instead" % lc)
+ providers[pname] = config.get(osys, 'en')
+ try:
+ #test = providers[pname].split("$")
+ #self.log.debug(test)
+ if osys == 'linux':
+ t32, t64 = [t for t in providers[pname].split(",") if t]
+
+ link, signature, chs32 = [l for l in t32.split("$") if l]
+ links32[link] = signature
+
+ link, signature, chs64 = [l for l in t64.split("$") if l]
+ links64[link] = signature
+
+ else:
+ link, signature, chs32 = [l for l in providers[pname].split("$") if l]
+ links32[link] = signature
+
+ #providers[pname] = providers[pname].replace(",", "")
+ #providers[pname] = providers[pname].replace("$", "\n\n")
# all packages are signed with same key
# (Tor Browser developers)
fingerprint = config.get('key', 'fingerprint')
- fingerprint_msg = self._get_msg('fingerprint', lc)
+ # for now, english messages only
+ fingerprint_msg = self._get_msg('fingerprint', 'en')
fingerprint_msg = fingerprint_msg % fingerprint
except ConfigParser.Error as e:
raise InternalError("%s" % str(e))
@@ -246,10 +277,47 @@ class Core(object):
# create the final links list with all providers
all_links = []
+ msg = "Tor Browser %s-bit:" % arch
+ for link in links32:
+ msg = "%s\n%s" % (msg, link)
+
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "\n\n\nTor Browser 64-bit:"
+ for link in links64:
+ msg = "%s\n%s" % (msg, link)
+
+ all_links.append(msg)
+
+ msg = "\n\n\nTor Browser's signature %s-bit (in the same order):" %\
+ arch
+ for link in links32:
+ msg = "%s\n%s" % (msg, links32[link])
+
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "\n\n\nTor Browser's signature 64-bit:"
+ for link in links64:
+ msg = "%s\n%s" % (msg, links64[link])
+
+ all_links.append(msg)
+
+ msg = "\n\n\nSHA256 of Tor Browser %s-bit (advanced): %s\n" %\
+ (arch, chs32)
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "SHA256 of Tor Browser 64-bit (advanced): %s\n" % chs64
+ all_links.append(msg)
+
+ """
for key in providers.keys():
# get more friendly description of the provider
try:
- provider_desc = self._get_msg('provider_desc', lc)
+ # for now, english messages only
+ provider_desc = self._get_msg('provider_desc', 'en')
provider_desc = provider_desc % key
all_links.append(
@@ -258,6 +326,7 @@ class Core(object):
)
except ConfigError as e:
raise InternalError("%s" % str(e))
+ """
# add fingerprint after the links
all_links.append(fingerprint_msg)
@@ -405,6 +474,7 @@ class Core(object):
"""Add request to database."""
self.log.debug("Trying to add request to database")
try:
+ self.db.connect()
self.db.add_request()
self.log.debug("Request added!")
except db.DBError as e:
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 4db3ac7..34477ef 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -76,7 +76,7 @@ class SMTP(object):
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
+ cfg = default_cfg
try:
with open(cfg) as f:
@@ -240,7 +240,12 @@ class SMTP(object):
"""
req = self._parse_text(msg)
lc = self._get_lc(addr)
- req['lc'] = lc
+ supported_lc = self.core.get_supported_lc()
+
+ if lc in supported_lc:
+ req['lc'] = lc
+ else:
+ req['lc'] = 'en'
return req
@@ -361,8 +366,8 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
try:
- links_subject = self._get_msg('links_subject', lc)
- links_msg = self._get_msg('links_msg', lc)
+ links_subject = self._get_msg('links_subject', 'en')
+ links_msg = self._get_msg('links_msg', 'en')
links_msg = links_msg % (os, lc, links)
self._send_email(
@@ -490,7 +495,7 @@ class SMTP(object):
self.log.debug("Trying to send help...")
# make sure we can send emails
try:
- self._send_help(req['lc'], our_addr, norm_from_addr)
+ self._send_help('en', our_addr, norm_from_addr)
status = 'success'
except SendEmailError as e:
status = 'internal_error'
@@ -503,7 +508,7 @@ class SMTP(object):
self.log.debug("Trying to send the mirrors...")
# make sure we can send emails
try:
- self._send_mirrors(req['lc'], our_addr, norm_from_addr)
+ self._send_mirrors('en', our_addr, norm_from_addr)
status = 'success'
except SendEmailError as e:
status = 'internal_error'
@@ -519,7 +524,7 @@ class SMTP(object):
'SMTP', req['os'], req['lc']
)
# if core fails, we fail too
- except (core.InternalError, core.ConfigurationError) as e:
+ except (core.InternalError, core.ConfigError) as e:
status = 'core_error'
self.log.debug("FAILED: %s" % str(e))
# something went wrong with the core
diff --git a/lang/core/i18n/en/en.po b/lang/core/i18n/en/en.po
index b8d4509..0b28a70 100644
--- a/lang/core/i18n/en/en.po
+++ b/lang/core/i18n/en/en.po
@@ -2,7 +2,7 @@ domain "en"
#: Fingerprint message
msgid "fingerprint"
-msgstr "Fingerprint of the key used to sign Tor Browser:\n%s"
+msgstr "Fingerprint of key used to sign Tor Browser (advanced): %s"
#: Provider description
msgid "provider_desc"
diff --git a/lang/smtp/i18n/en/LC_MESSAGES/en.po b/lang/smtp/i18n/en/LC_MESSAGES/en.po
index dcb2e35..ee6a24e 100644
--- a/lang/smtp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/smtp/i18n/en/LC_MESSAGES/en.po
@@ -28,6 +28,7 @@ Below are the links for your request (Tor Browser for %s, %s package):\n\
\n\
%s\n\
\n\
+===========================================================================\n\
Still need help? If you have any questions, trouble connecting to Tor\n\
network, or need to talk to a human, please contact our support team at:\n\
\n\
@@ -63,7 +64,8 @@ Please reply to this message with one of the options below:\n\
windows\n\
linux\n\
osx\n\
+ mirrors\n\
\n\
-And I will send you the download instructions quickly.\n\
+And I will send you the download/access instructions quickly.\n\
\n\
Tip: Just send a blank reply to this message if you are not sure."
1
0
commit e1fe0b98202d07aaacb14d0dc18bce8080642e67
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:14:55 2015 -0300
Better debugging and error handling
---
gettor/blacklist.py | 65 ++++++++++++++++++++++++---------------------------
gettor/db.py | 7 +++++-
2 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/gettor/blacklist.py b/gettor/blacklist.py
index a16c764..635d9a7 100644
--- a/gettor/blacklist.py
+++ b/gettor/blacklist.py
@@ -120,44 +120,41 @@ class Blacklist(object):
:raise: BlacklistError if the user is blacklisted
"""
- r = self.db.get_user(user, service)
- if r:
- # permanently blacklisted
- if r['blocked']:
- try:
+ try:
+ self.log.info("Trying to get info from user")
+ self.db.connect()
+ r = self.db.get_user(user, service)
+ if r:
+ # permanently blacklisted
+ if r['blocked']:
+ self.log.warning("Request from user permanently blocked")
self.db.update_user(user, service, r['times']+1, 1)
raise BlacklistError("Blocked user")
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- # don't be greedy
- elif r['times'] >= max_req:
- last = datetime.datetime.fromtimestamp(
- float(r['last_request'])
- )
- next = last + datetime.timedelta(minutes=wait_time)
-
- if datetime.datetime.now() < next:
- # too many requests from the same user
- try:
+ # don't be greedy
+ elif r['times'] >= max_req:
+ last = datetime.datetime.fromtimestamp(
+ float(r['last_request'])
+ )
+ next = last + datetime.timedelta(minutes=wait_time)
+
+ if datetime.datetime.now() < next:
+ self.log.warning("Too many requests from same user")
self.db.update_user(user, service, r['times']+1, 0)
raise BlacklistError("Too many requests")
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # fresh user again!
- try:
+ else:
+ # fresh user again!
+ self.log.info("Updating counter for existing user")
self.db.update_user(user, service, 1, 0)
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # adding up a request for user
- try:
+ else:
+ # adding up a request for user
+ self.log.info("Request from existing user")
self.db.update_user(user, service, r['times']+1, 0)
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # new request for user
- try:
+ else:
+ # new request for user
+ self.log.info("Request from new user")
self.db.add_user(user, service, 0)
- except db.DBError as e:
- raise InternalError("Can't add new user (%s)" % str(e))
+ except db.DBError as e:
+ self.log.error("Something failed!")
+ raise InternalError("Error with database (%s)" % str(e))
+ except BlacklistError as e:
+ raise BlacklistError(e)
diff --git a/gettor/db.py b/gettor/db.py
index 0b971af..7a595a3 100644
--- a/gettor/db.py
+++ b/gettor/db.py
@@ -44,8 +44,13 @@ class DB(object):
:param: dbname (string) the path of the database.
"""
+ self.dbname = dbname
+
+
+ def connect(self):
+ """ """
try:
- self.con = sqlite3.connect(dbname)
+ self.con = sqlite3.connect(self.dbname)
self.con.row_factory = sqlite3.Row
except sqlite3.Error as e:
raise DBError("%s" % str(e))
1
0

[gettor/master] Better debugging, error handling and mirrors option for xmpp
by ilv@torproject.org 03 Nov '15
by ilv@torproject.org 03 Nov '15
03 Nov '15
commit d71e6838bda2a158963228f321d1cb682c5f4297
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:17:21 2015 -0300
Better debugging, error handling and mirrors option for xmpp
---
gettor/xmpp.py | 200 +++++++++++++++++++++--------------
lang/xmpp/i18n/en/LC_MESSAGES/en.po | 72 +++++++++++--
process_chat.py | 22 ++++
xmpp.cfg | 2 +
4 files changed, 207 insertions(+), 89 deletions(-)
diff --git a/gettor/xmpp.py b/gettor/xmpp.py
index e9d2a10..f9b025d 100644
--- a/gettor/xmpp.py
+++ b/gettor/xmpp.py
@@ -5,8 +5,8 @@
# :authors: Israel Leiva <ilv(a)riseup.net>
# see also AUTHORS file
#
-# :copyright: (c) 2008-2014, The Tor Project, Inc.
-# (c) 2014, Israel Leiva
+# :copyright: (c) 2008-2015, The Tor Project, Inc.
+# (c) 2015, Israel Leiva
#
# :license: This is Free Software. See LICENSE for license information.
@@ -20,6 +20,7 @@ import logging
import ConfigParser
from sleekxmpp import ClientXMPP
+from sleekxmpp.xmlstream.stanzabase import JID
from sleekxmpp.exceptions import IqError, IqTimeout
import core
@@ -30,6 +31,14 @@ import blacklist
"""XMPP module for processing requests."""
+class ConfigError(Exception):
+ pass
+
+
+class InternalError(Exception):
+ pass
+
+
class Bot(ClientXMPP):
"""XMPP bot.
@@ -52,10 +61,11 @@ class Bot(ClientXMPP):
self.get_roster()
except IqError as err:
# error getting the roster
- # logging.error(err.iq['error']['condition'])
+ self.xmpp.log.error(err.iq['error']['condition'])
self.disconnect()
except IqTimeout:
# server is taking too long to respond
+ self.xmpp.log.error("Server is taking too long to respond")
self.disconnect()
def message(self, msg):
@@ -65,14 +75,6 @@ class Bot(ClientXMPP):
msg.reply(msg_to_send).send()
-class ConfigError(Exception):
- pass
-
-
-class InternalError(Exception):
- pass
-
-
class XMPP(object):
"""Receive and reply requests by XMPP.
@@ -95,75 +97,63 @@ class XMPP(object):
"""
# define a set of default values
- DEFAULT_CONFIG_FILE = 'xmpp.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'xmpp.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
-
- config.read(cfg)
+ cfg = default_cfg
try:
- self.user = config.get('account', 'user')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'user' from 'account'")
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
+ self.user = config.get('account', 'user')
self.password = config.get('account', 'password')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'password' from 'account'")
- try:
- self.core_cfg = config.get('general', 'core_cfg')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'core_cfg' from 'general'")
+ self.mirrors = config.get('general', 'mirrors')
+ self.max_words = config.get('general', 'max_words')
+ self.max_words = int(self.max_words)
+ core_cfg = config.get('general', 'core_cfg')
+ self.core = core.Core(core_cfg)
+ self.i18ndir = config.get('i18n', 'dir')
- try:
blacklist_cfg = config.get('blacklist', 'cfg')
- self.bl = blacklist_cfg
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'cfg' from 'blacklist'")
-
- try:
+ self.bl = blacklist.Blacklist(blacklist_cfg)
self.bl_max_req = config.get('blacklist', 'max_requests')
self.bl_max_req = int(self.bl_max_req)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'max_requests' from 'blacklist'")
-
- try:
self.bl_wait_time = config.get('blacklist', 'wait_time')
self.bl_wait_time = int(self.bl_wait_time)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'wait_time' from 'blacklist'")
-
- try:
- self.i18ndir = config.get('i18n', 'dir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'i18n'")
- try:
logdir = config.get('log', 'dir')
logfile = os.path.join(logdir, 'xmpp.log')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
-
- try:
loglevel = config.get('log', 'level')
+
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'level' from 'log'")
+ raise ConfigError("Configuration error: %s" % str(e))
+ except blacklist.ConfigError as e:
+ raise InternalError("Blacklist error: %s" % str(e))
+ except core.ConfigError as e:
+ raise InternalError("Core error: %s" % str(e))
+
+ # logging
+ log = logging.getLogger(__name__)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
+
+ log.info('Redirecting XMPP logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def start_bot(self):
"""Start the bot for handling requests.
@@ -171,6 +161,7 @@ class XMPP(object):
Start a new sleekxmpp bot.
"""
+ self.log.info("Starting the bot with account %s" % self.user)
xmpp = Bot(self.user, self.password, self)
xmpp.connect()
xmpp.process(block=True)
@@ -184,11 +175,11 @@ class XMPP(object):
"""
anon_acc = utils.get_sha256(account)
- bl = blacklist.Blacklist(self.bl)
try:
- bl.is_blacklisted(anon_acc, 'XMPP', self.bl_max_req,
- self.bl_wait_time)
+ self.bl.is_blacklisted(
+ anon_acc, 'XMPP', self.bl_max_req, self.bl_wait_time
+ )
return False
except blacklist.BlacklistError as e:
return True
@@ -203,13 +194,17 @@ class XMPP(object):
"""
# obtain the content in the proper language
- t = gettext.translation(lc, self.i18ndir, languages=[lc])
- _ = t.ugettext
+ self.log.debug("Trying to get translated text")
+ try:
+ t = gettext.translation(lc, self.i18ndir, languages=[lc])
+ _ = t.ugettext
- msgstr = _(msgid)
- return msgstr
+ msgstr = _(msgid)
+ return msgstr
+ except IOError as e:
+ raise ConfigError("%s" % str(e))
- def _parse_text(self, msg, core_obj):
+ def _parse_text(self, msg):
"""Parse the text part of a message.
Split the message in words and look for patterns for locale,
@@ -223,20 +218,21 @@ class XMPP(object):
"""
# core knows what OS are supported
- supported_os = core_obj.get_supported_os()
- supported_lc = core_obj.get_supported_lc()
+ supported_os = self.core.get_supported_os()
+ supported_lc = self.core.get_supported_lc()
+ self.log.debug("Parsing text")
# default values
req = {}
req['lc'] = 'en'
req['os'] = None
req['type'] = 'help'
+
found_lc = False
found_os = False
+ found_mirrors = False
# analyze every word
- # request shouldn't be more than 10 words long, so there should
- # be a limit for the amount of words
for word in msg.split(' '):
# look for lc and os
if not found_lc:
@@ -250,6 +246,14 @@ class XMPP(object):
found_os = True
req['os'] = os
req['type'] = 'links'
+ # mirrors
+ if not found_mirrors:
+ if re.match("mirrors?", word, re.IGNORECASE):
+ found_mirrors = True
+ req['type'] = 'mirrors'
+ if (found_lc and found_os) or (found_lc and found_mirrors):
+ break
+
return req
def parse_request(self, account, msg):
@@ -269,36 +273,70 @@ class XMPP(object):
reply = ''
status = ''
req = None
- core_obj = core.Core(self.core_cfg)
+ self.log.debug("Parsing request")
try:
if self._is_blacklisted(str(account)):
+ self.log.info("Request from blacklisted account!")
status = 'blacklisted'
bogus_request = True
+ # first let's find out how many words are in the message
+ # request shouldn't be longer than 3 words, but just in case
+ words = msg.split(' ')
+ if len(words) > self.max_words:
+ bogus_request = True
+ self.log.info("Message way too long")
+ status = 'error'
+ reply = self._get_msg('message_error', 'en')
+
if not bogus_request:
+ self.log.debug("Request seems legit, let's parse it")
# let's try to guess what the user is asking
- req = self._parse_text(str(msg), core_obj)
+ req = self._parse_text(str(msg))
if req['type'] == 'help':
+ self.log.debug("Type of request: help")
status = 'success'
- reply = self._get_msg('help', req['lc'])
- elif req['type'] == 'links':
+ reply = self._get_msg('help', 'en')
+
+ elif req['type'] == 'mirrors':
+ self.log.debug("Type of request: mirrors")
+ status = 'success'
+ reply = self._get_msg('mirrors', 'en')
try:
- links = core_obj.get_links("XMPP", req['os'],
- req['lc'])
- reply = self._get_msg('links', req['lc'])
- reply = reply % (req['os'], req['lc'], links)
-
- status = 'success'
- except (core.ConfigError, core.InternalError) as e:
- # if core failes, send the user an error message, but
- # keep going
- status = 'core_error'
- reply = self._get_msg('internal_error', req['lc'])
+ with open(self.mirrors, "r") as list_mirrors:
+ mirrors = list_mirrors.read()
+ reply = reply % mirrors
+ except IOError as e:
+ reply = self._get_msg('mirrors_unavailable', 'en')
+
+ elif req['type'] == 'links':
+ self.log.debug("Type of request: help")
+ links = self.core.get_links(
+ "XMPP",
+ req['os'],
+ req['lc']
+ )
+ reply = self._get_msg('links', 'en')
+ reply = reply % (req['os'], req['lc'], links)
+
+ status = 'success'
+
+ except (core.ConfigError, core.InternalError) as e:
+ # if core failes, send the user an error message, but keep going
+ self.log.error("Something went wrong internally: %s" % str(e))
+ status = 'core_error'
+ reply = self._get_msg('internal_error', req['lc'])
+
finally:
# keep stats
if req:
- core_obj.add_request_to_db()
+ self.log.debug("Adding request to database... ")
+ self.core.add_request_to_db()
+ if reply:
+ self.log.debug("Everything seems OK. Sending back the reply")
+ else:
+ self.log.debug("Nothing to reply!")
return reply
diff --git a/lang/xmpp/i18n/en/LC_MESSAGES/en.po b/lang/xmpp/i18n/en/LC_MESSAGES/en.po
index d242625..8cc715e 100644
--- a/lang/xmpp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/xmpp/i18n/en/LC_MESSAGES/en.po
@@ -2,21 +2,77 @@ domain "en"
#: Links
msgid "links"
-msgstr "Links %s-%s:\n %s"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Below are the links for your request (Tor Browser for %s, %s package):\n\
+\n\
+%s\n\
+\n\
+===========================================================================\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
-#: Links
-msgid "links_pt"
-msgstr "Links-PT for %s-%s:\n %s"
+#: Mirrors message
+msgid "mirrors"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. Below you will find an updated list of mirrors\n\
+of Tor Project's website.\n\
+\n\
+%s\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
#: Help
msgid "help"
-msgstr "*help*"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. I am here to help you download the latest\n\
+Tor Browser.\n\
+\n\
+Please reply to this message with one of the options below (where lc stands\n\
+for the locale of the package you want e.g. en):\n\
+\n\
+ windows lc\n\
+ linux lc\n\
+ osx lc\n\
+ mirrors\n\
+\n\
+The currently supported locales are:\n\
+\n\
+ en: English\n\
+\n\
+And I will send you the download/access instructions quickly."
-#: Unsupported locale
-msgid "unsupported_lc"
-msgstr "Unsupported locale"
+#: Mirrors unavailable message
+msgid "mirrors_unavailable"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+I'm sorry, I can't send you mirrors right now, please try again later.\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
#: Internal error
msgid "internal_error"
msgstr "Internal error"
+#: Internal error
+msgid "message_error"
+msgstr "Message too long."
diff --git a/process_chat.py b/process_chat.py
new file mode 100644
index 0000000..6ad7b59
--- /dev/null
+++ b/process_chat.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+import logging
+
+import gettor.xmpp
+
+def main():
+ try:
+ bot = gettor.xmpp.XMPP()
+ bot.start_bot()
+ except gettor.xmpp.ConfigError as e:
+ print "Configuration error: %s" % str(e)
+ except gettor.xmpp.InternalError as e:
+ print "Core module not working: %s" % str(e)
+ except Exception as e:
+ # in case something unexpected happens
+ print "Unexpected error: %s" % str(e)
+
+if __name__ == '__main__':
+ main()
diff --git a/xmpp.cfg b/xmpp.cfg
index 0b2f547..d81d4df 100644
--- a/xmpp.cfg
+++ b/xmpp.cfg
@@ -5,6 +5,8 @@ password:
[general]
basedir: /path/to/gettor/xmpp/
core_cfg: /path/to/core.cfg
+max_words: 10
+db: /path/to/gettor.db
[blacklist]
cfg: /path/to/blacklist.cfg
1
0
commit 54ebdf8ec2110dd381e66e07349add7ead190dce
Author: ilv <ilv(a)users.noreply.github.com>
Date: Tue Nov 3 16:06:56 2015 -0300
Change related to #17211
---
gettor/xmpp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gettor/xmpp.py b/gettor/xmpp.py
index f9b025d..a605f50 100644
--- a/gettor/xmpp.py
+++ b/gettor/xmpp.py
@@ -283,7 +283,7 @@ class XMPP(object):
# first let's find out how many words are in the message
# request shouldn't be longer than 3 words, but just in case
- words = msg.split(' ')
+ words = re.split('\s+', msg.strip())
if len(words) > self.max_words:
bogus_request = True
self.log.info("Message way too long")
1
0
commit 540c525cb038ff42684488f4a1b3f4c5078b5b8e
Author: ilv <ilv(a)users.noreply.github.com>
Date: Tue Nov 3 16:06:20 2015 -0300
Minor correction to #17211
---
gettor/smtp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 5476189..3697786 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -271,7 +271,7 @@ class SMTP(object):
# search for OS or mirrors request
# if nothing is found, help by default
found_request = False
- words = re.split('\s+', test.strip())
+ words = re.split('\s+', msg.strip())
for word in words:
if not found_request:
# OS first
1
0

[torspec/master] Rewrite the existing PT spec to be not Tor specific.
by nickm@torproject.org 03 Nov '15
by nickm@torproject.org 03 Nov '15
03 Nov '15
commit 0ef45b97b1a935489335fc31d625c463b076c1e3
Author: Yawning Angel <yawning(a)torproject.org>
Date: Tue Nov 3 17:34:43 2015 +0000
Rewrite the existing PT spec to be not Tor specific.
This attempts to make it clear that PTs are not just for Tor, and can
be used by any project, and should be sufficient documentation for
writing the PT glue code both for Tor and other projects.
TODO: Fold in the implemented parts of prop 196/217. I'll do this when
I have time, since statistics are useful for everybody.
Fixes: #13369, #15545
Completes: #16754
---
pt-spec.txt | 1026 ++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 636 insertions(+), 390 deletions(-)
diff --git a/pt-spec.txt b/pt-spec.txt
index 43ae73f..aa723aa 100644
--- a/pt-spec.txt
+++ b/pt-spec.txt
@@ -1,494 +1,740 @@
- Tor Pluggable Transport Specification
+ Pluggable Transport Specification (Version 1)
+
+Abstract
+
+ Pluggable Transports (PTs) are a generic mechanism for the rapid
+ development and deployment of censorship circumvention,
+ based around the idea of modular sub-processes that transform
+ traffic to defeat censors.
+
+ This document specifies the sub-process startup, shutdown,
+ and inter-process communication mechanisms required to utilize
+ PTs.
+
+Table of Contents
+
+ 1. Introduction
+ 1.1. Requirements Notation
+ 2. Architecture Overview
+ 3. Specification
+ 3.1. Pluggable Transport Naming
+ 3.2. Pluggable Transport Configuration Environment Variables
+ 3.2.1. Common Environment Variables
+ 3.2.2. Pluggable Transport Client Environment Variables
+ 3.2.3. Pluggable Transport Server Environment Variables
+ 3.3. Pluggable Transport To Parent Process Communication
+ 3.3.1. Common Messages
+ 3.3.2. Pluggable Transport Client Messages
+ 3.3.3. Pluggable Transport Server Messages
+ 3.4. Pluggable Transport Shutdown
+ 3.5. Pluggable Transport Client Per-Connection Arguments
+ 4. Anonymity Considerations
+ 5 References
+ 6. Acknowledgments
+ Appendix A. Example Client Pluggable Transport Session
+ Appendix B. Example Server Pluggable Transport Session
+
+1. Introduction
+
+ This specification describes a way to decouple protocol-level
+ obfuscation from an application's client/server code, in a manner
+ that promotes rapid development of obfuscation/circumvention
+ tools and promotes reuse beyond the scope of the Tor Project's
+ efforts in that area.
+
+ This is accomplished by utilizing helper sub-processes that
+ implement the necessary forward/reverse proxy servers that handle
+ the censorship circumvention, with a well defined and
+ standardized configuration and management interface.
+
+ Any application code that implements the interfaces as specified
+ in this document will be able to use all spec compliant Pluggable
+ Transports.
+
+1.1. Requirements Notation
- The Tor PT team
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
+ NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in
+ [RFC2119].
+
+2. Architecture Overview
-A Table of Contents:
+ +------------+ +---------------------------+
+ | Client App +-- Local Loopback --+ PT Client (SOCKS Proxy) +--+
+ +------------+ +---------------------------+ |
+ |
+ Public Internet (Obfuscated/Transformed traffic) ==> |
+ |
+ +------------+ +---------------------------+ |
+ | Server App +-- Local Loopback --+ PT Server (Reverse Proxy) +--+
+ +------------+ +---------------------------+
- 0. Motivation
- 1. Tor PT interface overview
- 2. Specification
- 2.0. Pluggable Transport names
- 2.1. Tor Configuration
- 2.1.0. Client Configuration
- 2.1.0.0. ClientTransportPlugin torrc lines
- 2.1.0.1. Bridge torrc lines
- 2.1.0.2. Connecting to a bridge via a client PT proxy
- 2.1.0.3. Passing PT-specific parameters to a client PT
- 2.1.1. Server (bridge) Configuration
- 2.1.1.0. ServerTransportPlugin lines
- 2.1.1.1. Passing PT-specific parameters to a server PT
- 2.1.1.2. Specify the bind address of a server PT
- 2.2. Managed proxy interface
- 2.2.0. Tor -> PT communication (environment variables)
- 2.2.1. PT -> Tor communication (stdout)
- 2.2.1.0. Client PT behaviour (CMETHOD lines)
- 2.2.1.1. Server PT behaviour (SMETHOD lines)
- 2.2.2. Managed proxy protocol behaviour
+ On the client's host, the PT Client software exposes a SOCKS proxy
+ [RFC1928] to the client application, and obfuscates or otherwise
+ transforms traffic before forwarding it to the server's host.
- +---- Extended ORPort
- | connection
- v
- +-----------+ +------------+
- SOCKS -> +-----| PT client |------------| PT server |----+
-connection | +-----------+ ^ +------------+ |
- | | |
- +------------+ Obfuscated +--------------+
- | Tor Client | traffic | Tor Bridge |
- +------------+ +--------------+
+ On the server's host, the PT Server software exposes a reverse proxy
+ that accepts connections from PT Clients, and handles reversing the
+ obfuscation/transformation applied to traffic, before forwarding it
+ to the actual server software. An optional lightweight protocol
+ exists to facilitate communicating connection meta-data that would
+ otherwise be lost such as the source IP address and port
+ [EXTORPORT].
+ All PT instances are configured by the respective parent process via
+ a set of standardized environment variables (3.2) that are set at
+ launch time, and report status information back to the parent via
+ writing output in a standardized format to stdout (3.3).
+ Each invocation of a PT MUST be either a client OR a server.
-0. Motivation
+ All PT client forward proxies MUST support either SOCKS 4 or SOCKS 5,
+ and SHOULD prefer SOCKS 5 over SOCKS 4.
- This specification describes how Tor uses Pluggable Transports (PTs).
- This document is different from pt-spec.txt because it contains
- Tor-specific information, whereas the pt-spec.txt aims to be
- system-independent.
+3. Specification
-1. Tor PT interface overview
+ Pluggable Transport proxies follow the following workflow
+ throughout their lifespan.
- Pluggable Transports must implement a specific interface to be able to
- harmoniously coordinate with Tor. This article attempts to document
- this interface.
+ 1) Parent process sets the required environment values (3.2)
+ and launches the PT proxy as a sub-process (fork()/exec()).
- TODO: Make this section more useful (SOCKS, ExtORport, etc.)
+ 2) The PT Proxy determines the versions of the PT specification
+ supported by the parent"TOR_PT_MANAGED_TRANSPORT_VER" (3.2.1)
-2. Specification
+ 2.1) If there are no compatible versions, the PT proxy
+ writes a "VERSION-ERROR" message (3.3.1) to stdout and
+ terminates.
-2.0. Pluggable Transport names
+ 2.2) If there is a compatible version, the PT proxy writes
+ a "VERSION" message (3.3.1) to stdout.
- Tor treats Pluggable Transport names as unique identifiers. Every PT
- MUST have a unique name.
+ 3) The PT Proxy parses the rest of the environment values.
- Furthermore, PT names MUST be C identifiers. That is, PT names MUST
- begin with a letter or underscore and the rest of the characters be
- letters, numbers or underscores. No length limit is imposed.
+ 3.1) If the environment values are malformed, or otherwise
+ invalid, the PT proxy writes a "ENV-ERROR" message
+ (3.3.1) to stdout and terminates.
- PT names MUST satisfy the regular expression "[a-zA-Z_][a-zA-Z0-9_]*".
+ 3.2) Determining if it is a client side forward proxy or
+ a server side reverse proxy can be done via examining
+ the "TOR_PT_CLIENT_TRANSPORTS" and "TOR_PT_SERVER_TRANSPORTS"
+ environment variables.
-2.1. Tor Configuration
+ 4) (Client only) If there is an upstream proxy specified via
+ "TOR_PT_PROXY" (3.2.2), the PT proxy validates the URI
+ provided.
-2.1.0. Client Configuration
+ 4.1) If the upstream proxy is unusable, the PT proxy writes
+ a "PROXY-ERROR" message (3.3.2) to stdout and
+ terminates.
- Users use the Tor configuration file (torrc) to specify if and how
- Pluggable Transports should be used. Specifically, a user is expected
- to use the Bridge and ClientTransportPlugin torrc lines to configure
- their PTs.
+ 4.2) If there is a supported and well-formed upstream proxy
+ the PT proxy writes a "PROXY DONE" message (3.3.2) to
+ stdout.
-2.1.0.0. ClientTransportPlugin torrc lines
+ 5) The PT Proxy initializes the transports and reports the
+ status via stdout (3.3.2, 3.3.3)
- ClientTranportPlugin torrc lines are used by Tor to configure
- Pluggable Transports. They specify the location of the PT executable,
- and which PT protocols the executable is able to perform.
+ 6) The PT Proxy forwards and transforms traffic as appropriate.
- The standard format of a ClientTransportPlugin line is:
+ 7) Upon being signaled to terminate by the parent process (3.4),
+ the PT Proxy gracefully shuts down.
- ClientTransportPlugin <transports> exec <path> [<options>]
+3.1. Pluggable Transport Naming
- where <transports> are the (comma-separated) names of the PTs that
- this line specifies. <path> is a filesystem path pointing to an
- executable that can "perform" this PT. <options> are (optional)
- command-line arguments and switches that should be used when
- invoking the executable.
+ Pluggable Transport names serve as unique identifiers, and every
+ PT MUST have a unique name.
- For example:
+ PT names MUST be valid C identifiers. PT names MUST begin with
+ a letter or underscore, and the remaining characters MUST be
+ ASCII letters, numbers or underscores. No length limit is
+ imposted.
- ClientTransportPlugin obfs2,obfs3 exec /usr/bin/obfsproxy --managed
+ PT names MUST satisfy the regular expression "[a-zA-Z_][a-zA-Z0-9_]*".
- This line tells Tor to launch the executable "/usr/bin/obfsproxy" with
- the command-line switch "--managed". That executable should be able to
- perform two PTs: obfs2 and obfs3.
+3.2. Pluggable Transport Configuration Environment Variables
- If two ClientTransportPlugin lines specify the same PT, Tor SHOULD use
- whichever one is listed first.
+ All Pluggable Transport proxy instances are configured by their
+ parent process at launch time via a set of well defined
+ environment variables.
- TODO: Document external mode
+ The "TOR_PT_" prefix is used for namespacing reasons and does not
+ indicate any relations to Tor, except for the origins of this
+ specification.
-2.1.0.1. Bridge torrc lines
+3.2.1. Common Environment Variables
- Bridge lines specify how Tor should connect to a bridge. The Bridge
- line format is:
+ When launching either a client or server Pluggable Transport proxy,
+ the following common environment variables MUST be set.
- Bridge [<transport>] <address>:<port> [<id-fingerprint>] [<k>=<v>] [<k>=<v>] [<k>=<v>]
+ "TOR_PT_MANAGED_TRANSPORT_VER"
- The PT-specific parts of this format are the [transport] and [k=v]
- values.
+ Specifies the versions of the Pluggable Transport specification
+ the parent process supports, delimited by commas. All PTs MUST
+ accept any well-formed list, as long as a compatible version is
+ present.
- <transport> is the name of the PT that MUST be used when connecting to
- the bridge, and the <k>=<v> values are PT-specific parameters that
- MUST be passed to the PT when connecting to the bridge (this MAY
- include keys, passwords or other PT configuration options) as
- specified in [CLIENTPARAMS].
+ Valid versions MUST consist entirely of non-whitespace,
+ non-comma printable ASCII characters.
- Upon encountering such a Bridge line in the torrc, Tor iterates over
- the ClientTransportPlugin lines and checks if there is a line that
- specifies how <transport> is performed.
+ The version of the Pluggable Transport specification as of this
+ document is "1".
- If a corresponding ClientTransportPlugin line is found, Tor is
- expected to execute and enable that PT via the process specified in
- [MANAGEDPROXY]. If no such line could be found, Tor SHOULD warn the
- user that there is no way to perform that PT.
+ Example:
- When a PT-supporting bridge needs to be used in a Tor circuit, Tor
- uses the PT as a proxy as specified in 2.1.0.2.
+ TOR_PT_MANAGED_TRANSPORT_VER=1,1a,2b,this_is_a_valid_ver
-2.1.0.2. Connecting to a bridge via a client PT proxy
+ "TOR_PT_STATE_LOCATION"
- Consider a fictitious example of the torrc lines:
+ Specifies an absolute path to a directory where the PT is
+ allowed to store state that will be persisted across
+ invocations. The directory is not required to exist when
+ the PT is launched, however PT implementations SHOULD be
+ able to create it as required.
- ClientTransportPlugin btc,ltc exec /usr/bin/btcproxy
- Bridge btc 192.0.2.1:6612 tx_size=0.2
+ PTs MUST only store files in the path provided, and MUST NOT
+ create or modify files elsewhere on the system.
- In this example, to connect to the bridge at 192.0.2.1:6612, Tor is
- expected to use the PT "btc" via the PT proxy at /usr/bin/btcproxy.
+ Example:
- Using the managed proxy protocol (specified in [MANAGEDPROXY]), the PT
- proxy exposes a SOCKS proxy server and informs Tor of the address.
- Tor connects to 192.0.2.1:6612 via the PT SOCKS proxy and routes
- regular Tor traffic through the SOCKS connection. The PT proxy is
- expected to transform the Tor traffic to and from the bridge.
+ TOR_PT_STATE_LOCATION=/var/lib/tor/pt_state/
- Furthermore, as "tx_size=0.2" was specified as a PT-specific
- parameter, Tor will pass that to the PT proxy via the method specified
- in [CLIENTPARAMS].
+ "TOR_PT_EXIT_ON_STDIN_CLOSE"
-2.1.0.3. Passing PT-specific parameters to a client PT [CLIENTPARAMS]
+ Specifies that the parent process will close the PT proxy's
+ standard input (stdin) stream to indicate that the PT proxy
+ should gracefully exit.
- If PT-specific parameters are specified in a Bridge line, Tor MUST
- pass them to the PT proxy every time a connection is made to that
- bridge.
+ PTs MUST NOT treat a closed stdin as a signal to terminate
+ unless this environment variable is set to "1".
- To do so, the authentication mechanism of the SOCKS protocol is
- (ab)used. Specifically, if any <k>=<v> values are specified in a
- Bridge line, Tor should join them with semicolons and place them in
- the user and password fields of the SOCKS handshake (splitting them
- across the fields if needed). If a key or value contains a semicolon
- or a backslash, it is escaped with a backslash.
+ PTs SHOULD treat stdin being closed as a signal to gracefully
+ terminate if this environment variable is set to "1".
- For example:
+ Example:
- Bridge trebuchet 192.0.2.1:6612 rocks=20 height=5.6m
+ TOR_PT_EXIT_ON_STDIN_CLOSE=1
- when connecting to that bridge, Tor is expected to encode the PT
- parameters in the SOCKS handshake as the following string:
+3.2.2. Pluggable Transport Client Environment Variables
- rocks=20;height=5.6m
+ Client-side Pluggable Transport forward proxies are configured
+ via the following environment variables.
-2.1.1. Server (bridge) Configuration
+ "TOR_PT_CLIENT_TRANSPORTS"
- Server-side PTs are configured similarly to client proxies. Bridge
- operators use ServerTransportPlugin lines to configure their PTs.
+ Specifies the PT protocols the client proxy should initialize,
+ as a comma separated list of PT names.
- If a server-side PT requires additional parameters, they need to be
- specified using the ServerTransportOptions torrc parameter.
+ PTs SHOULD ignore PT names that it does not recognize.
- Also, instead of using the ORPort, server PTs SHOULD use the
- Extended ORPort to pass data to Tor. The Extended ORPort protocol is
- an ORPort enhanced with an additional metadata channel to carry
- various metadata about client connections (which PT was used, what
- was the actual IP of the client, etc.). The Extended ORPort is
- specified in [EXTORPORT].
+ Parent processes MUST set this environment variable when
+ launching a client-side PT proxy instance.
-2.1.1.0. ServerTransportPlugin lines
+ Example:
- ServerTransportPlugin lines are used to tell Tor about pluggable
- transports. They specify where a PT can be found if it needs to
- provide service for a Tor bridge.
+ TOR_PT_CLIENT_TRANSPORTS=obfs2,obfs3,obfs4
- The standard format of a ServerTransportPlugin line is:
+ "TOR_PT_PROXY"
- ServerTransportPlugin <transports> exec <path> [<options>]
+ Specifies an upstream proxy that the PT MUST use when making
+ outgoing network connections. It is a URI [RFC3986] of the
+ format:
- with the same format as ClientTransportPlugin lines.That is,
- <transports> are the (comma-separated) names of the PTs that this
- line specifies. <path> is a filesystem path pointing to an
- executable that can "perform" this PT. <options> are command-line
- arguments and switches that should be used when calling the
- executable.
+ <proxy_type>://[<user_name>[:<password>][@]<ip>:<port>.
- Upon encountering a ServerTransportPlugin line, Tor needs to launch
- and configure the corresponding PT using the managed proxy protocol
- (as specified in [MANAGEDPROXY]).
+ The "TOR_PT_PROXY" environment variable is OPTIONAL and
+ MUST be omitted if there is no need to connect via an
+ upstream proxy.
-2.1.1.1. Passing PT-specific parameters to a server PT
+ Examples:
- Further configuration parameters (like the <k>=<v> values passed to
- client PTs using Bridge lines) can be passed to server PTs using the
- ServerTransportOptions option.
+ TOR_PT_PROXY=socks5://tor:test1234@198.51.100.1:8000
+ TOR_PT_PROXY=socks4a://198.51.100.2:8001
+ TOR_PT_PROXY=http://198.51.100.3:443
- The format of the ServerTransportOptions line is:
- ServerTransportOptions <transport> <k=v> ...
+3.2.3. Pluggable Transport Server Environment Variables
- For example, a valid instance of this line would be:
- ServerTransportOptions hieroglyphics locale=egypt
- which would pass the parameter "locale=egypt" to the hieroglyphics PT.
+ Server-side Pluggable Transport reverse proxies are configured
+ via the following environment variables.
- In contrast to the client PT parameters, the server PT parameters
- are valid for the whole runtime of the PT, instead of only being
- used per-connection. They are passed to the PT proxy using the
- managed proxy protocol (as specified in [MANAGEDPROXY]).
+ "TOR_PT_SERVER_TRANSPORTS"
-2.1.1.2. Specify the bind address of a server PT
+ Specifies the PT protocols the server proxy should initialize,
+ as a comma separated list of PT names.
- By default, server PTs will bind to IPADDR_ANY and to a random TCP
- port the first time they get launched and will attempt to bind to
- the same port in subsequent runs.
+ PTs SHOULD ignore PT names that it does not recognize.
- A bridge operator that wants to specify a different address or port
- should use the ServerTransportListenAddr torrc line. The format of
- such a line is:
- ServerTransportListenAddr <transport> <address:port>
+ Parent processes MUST set this environment variable when
+ launching a server-side PT reverse proxy instance.
- For example, some valid instances of this line would be:
- ServerTransportListenAddr rot26 98.23.4.45:4200
- ServerTransportListenAddr sound_pt [::]:1025
+ Example:
-2.2. Launching PT proxies (managed proxy protocol) [MANAGEDPROXY]
+ TOR_PT_SERVER_TRANSPORTS=obfs3,scramblesuit
- When Tor is instructed to enable a PT, it launches the executable
- file specified in the ClientTransportPlugin line or the
- ServerTransportPlugin line. This can be done using execve(2) or any
- other process-spawning API.
+ "TOR_PT_SERVER_TRANSPORT_OPTIONS"
- After Tor has launched the PT, the PT must be configured to ensure
- that the right transports will be used, that it will bind in the
- proper address/port, etc.
+ Specifies per-PT protocol configuration directives, as a
+ semicolon-separated list of <key>:<value> pairs, where <key>
+ is a PT name and <value> is a k=v string value with options
+ that are to be passed to the transport.
- To achieve this, Tor and the PT use the "managed proxy protocol". This
- is a communication protocol where Tor speaks to the PT using
- environment variables, and the PT replies by printing lines to its
- stdout.
+ Colons, semicolons, equal signs and backslashes MUST be
+ escaped with a backslash.
-2.2.0. Tor -> PT communication (environment variables)
+ If there are no arguments that need to be passed to any of
+ PT transport protocols, "TOR_PT_SERVER_TRANSPORT_OPTIONS"
+ MAY be omitted.
+
+ Example:
+
+ TOR_PT_SERVER_TRANSPORT_OPTIONS=scramblesuit:key=banana;automata:rule=110;automata:depth=3
- When the Tor client or relay launches a managed proxy, it communicates
- via environment variables. At a minimum, TOR MUST set the following
- enviornment variables:
+ Will pass to 'scramblesuit' the parameter 'key=banana' and to
+ 'automata' the arguments 'rule=110' and 'depth=3'.
- {Both client and server}
+ "TOR_PT_SERVER_BINDADDR"
- "TOR_PT_STATE_LOCATION" -- A filesystem directory path where the
- PT is allowed to store permanent state if required. This
- directory is not required to exist, but the proxy SHOULD be able
- to create it if it does not. The proxy MUST NOT store state
- elsewhere.
- Example: TOR_PT_STATE_LOCATION=/var/lib/tor/pt_state/
+ A comma separated list of <key>-<value> pairs, where <key> is
+ a PT name and <value> is the <address>:<port> on which it
+ should listen for incoming client connections.
- "TOR_PT_MANAGED_TRANSPORT_VER" -- Used to tell the proxy which
- versions of this configuration protocol Tor supports. Clients
- MUST accept comma-separated lists containing any version that
- they recognise, and MUST work correctly even if some of the
- versions they do not recognise are non-numeric. Valid version
- characters are non-space, non-comma printable ASCII characters.
- Example: TOR_PT_MANAGED_TRANSPORT_VER=1,1a,2,4B
-
- {Client only}
-
- "TOR_PT_CLIENT_TRANSPORTS" -- A comma-separated list of the PTs
- this client should enable. The proxy SHOULD ignore transport
- names that it doesn't recognise.
- Example: TOR_PT_CLIENT_TRANSPORTS=trebuchet,battering_ram,ballista
-
- "TOR_PT_PROXY" -- This is the address of an outgoing proxy that
- the pluggable transport proxy MUST use (see proposal 232 for more
- details). It is of the format:
- <proxy_type>://[<user_name>][:<password>][@]<ip>:<port>
- The TOR_PT_PROXY is optional and MAY be omitted if there is no
- need to connect via an outgoing proxy.
- Example: socks5://tor:test1234@198.51.100.1:8000
- socks4a://198.51.100.2:8001
-
- {Server only}
-
- "TOR_PT_EXTENDED_SERVER_PORT" -- An <address>:<port> where Tor
- should be listening for connections speaking the extended
- ORPort protocol (as specified in [EXTORPORT]). If Tor does not
- support the extended ORPort protocol, it MUST use the empty
- string as the value of this environment variable.
- Example: TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200
-
- "TOR_PT_ORPORT" -- The <address>:<port> of the ORPort of the
- bridge where the PT is supposed to send the deobfuscated
- traffic.
- Example: TOR_PT_ORPORT=127.0.0.1:9001
-
- "TOR_PT_SERVER_BINDADDR" -- A comma separated list of
- <key>-<value> pairs, where <key> is a transport name and
- <value> is the adress:port on which it should listen for client
- proxy connections.
The keys holding transport names MUST be in the same order as
- they are in TOR_PT_SERVER_TRANSPORTS. This might be the
- advertised address, or might be a local address that Tor will
- forward ports to. It MUST be an address that will work with
- bind().
- Example:
- TOR_PT_SERVER_BINDADDR=trebuchet-127.0.0.1:1984,ballista-127.0.0.1:4891
-
- "TOR_PT_SERVER_TRANSPORTS" -- A comma-separated list of server
- transports that the proxy should support. The proxy SHOULD
- ignore transport names that it doesn't recognise.
- Example: TOR_PT_SERVER_TRANSPORTS=trebuchet,ballista
-
- "TOR_PT_AUTH_COOKIE_FILE" -- A filesystem path where the proxy
- should expect to find the authentication cookie to be able to
- communicate with the Extended ORPort and TransportControlPort.
- TOR_PT_AUTH_COOKIE_FILE is optional and might not be present in
- the environment of the proxy.
- Example: TOR_PT_AUTH_COOKIE_FILE=/var/lib/tor/extended_orport_auth_cookie
-
- "TOR_PT_SERVER_TRANSPORT_OPTIONS" -- A semicolon-separated list
- of <key>:<value> pairs, where <key> is a transport name and
- <value> is a k=v string value with options that are to be passed
- to the transport. Colons, semicolons, equal signs and backslashes
- MUST be escaped with a backslash. TOR_PT_SERVER_TRANSPORT_OPTIONS
- is optional and might not be present in the environment of the
- proxy if no options are need to be passed to transports.
+ they appear in "TOR_PT_SERVER_TRANSPORTS".
+
+ The <address> MAY be a locally scoped address as long as port
+ forwarding is done externally.
+
+ The <address>:<port> combination MUST be an IP address
+ supported by `bind()`, and MUST NOT be a host name.
+
+ Applications MUST NOT set more than one <address>:<port> pair
+ per PT name.
+
+ If there is no specific <address>:<port> combination to be
+ configured for any transports, "TOR_PT_SERVER_BINDADDR" MAY
+ be omitted.
+
Example:
- TOR_PT_SERVER_TRANSPORT_OPTIONS=scramblesuit:key=banana;automata:rule=110;automata:depth=3
- will pass to 'scramblesuit' the parameter 'key=banana' and to
- 'automata' the arguments 'rule=110' and 'depth=3'.
-
-2.2.1. PT -> Tor communication (stdout)
-
- The transport proxy replies by writing NL-terminated lines to
- stdout. The line metaformat is:
-
- <Line> ::= <Keyword> <OptArgs> <NL>
- <Keyword> ::= <KeywordChar> | <Keyword> <KeywordChar>
- <KeyWordChar> ::= <any US-ASCII alphanumeric, dash, and underscore>
- <OptArgs> ::= <Args>*
- <Args> ::= <SP> <ArgChar> | <Args> <ArgChar>
- <ArgChar> ::= <any US-ASCII character but NUL or NL>
- <SP> ::= <US-ASCII whitespace symbol (32)>
- <NL> ::= <US-ASCII newline (line feed) character (10)>
-
- Tor MUST ignore lines with keywords that it does not recognize.
-
- If there is an error parsing the environment variables, the proxy
- SHOULD write:
- ENV-ERROR <errormessage>
- and exit.
-
- If the environment variables were correctly formatted, the proxy
- should write:
- VERSION <configuration protocol version>
- to announce the supported configuration protocol version (eg:
- "VERSION 1"). It MUST either pick a version among those listed in the
- TOR_PT_MANAGED_TRANSPORT_VER enviornment variable. If no supported
- versions are listed in the enviornment variable the proxy SHOULD
- write:
- VERSION-ERROR no-version
- and exit.
-
- The proxy should then open its ports. If running as a client
- proxy, it SHOULD NOT use fixed ports; instead it SHOULD autoselect
- ports to avoid conflicts. A client proxy SHOULD only listen on the
- loopback interface for connections by default.
-
- A PT should then tell which transports it has made available and how.
- It does this by printing zero or more CMETHOD (client) or SMETHOD
- (server) lines to its stdout.
-
-2.2.1.0. Client PT behaviour
-
-2.2.1.0.0. Client PT outgoing proxy (PROXY lines)
-
- If the client PT is provided with a TOR_PT_PROXY environment variable,
- it MUST make all outgoing network connections via the supplied proxy.
- If it is unable to do so for any reason (eg: malformed value,
- unsupported proxy type, unreachable proxy address), it MUST return a
- `PROXY_ERROR` and terminate.
-
- If the value of the TOR_PT_PROXY environment variable is a proxy URL
- usable by the pluggable transport plugin (as specified by proposal
- 232-pluggable-transports-through-proxy.txt), the plugin writes to
- stdout:
+
+ TOR_PT_SERVER_BINDADDR=obfs3-198.51.100.1:1984,scramblesuit-127.0.0.1:4891
+
+ "TOR_PT_ORPORT"
+
+ Specifies the destination that the PT reverse proxy should forward
+ traffic to after transforming it as appropriate, as an
+ <address>:<port>.
+
+ Connections to the destination specified via "TOR_PT_ORPORT"
+ MUST only contain application payload. If the parent process
+ requires the actual source IP address of client connections
+ (or other metadata), it should set "TOR_PT_EXTENDED_SERVER_PORT"
+ instead.
+
+ Example:
+
+ TOR_PT_ORPORT=127.0.0.1:9001
+
+ "TOR_PT_EXTENDED_SERVER_PORT"
+
+ Specifies the destination that the PT reverse proxy should
+ forward traffic to, via the Extended ORPort protocol [EXTORPORT]
+ as an <address>:<port>.
+
+ The Extended ORPort protocol allows the PT reverse proxy to
+ communicate per-connection metadata such as the PT name and
+ client IP address/port to the parent process.
+
+ If the parent process does not support the ExtORPort protocol,
+ it MUST set "TOR_PT_EXTENDED_SERVER_PORT" to an empty string.
+
+ Example:
+
+ TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200
+
+ "TOR_PT_AUTH_COOKIE_FILE"
+
+ Specifies an absolute filesystem path to the Extended ORPort
+ authentication cookie, required to communicate with the
+ Extended ORPort specified via "TOR_PT_EXTENDED_SERVER_PORT".
+
+ If the parent process is not using the ExtORPort protocol for
+ incoming traffic, "TOR_PT_AUTH_COOKIE_FILE" MUST be omitted.
+
+ Example:
+
+ TOR_PT_AUTH_COOKIE_FILE=/var/lib/tor/extended_orport_auth_cookie
+
+3.3. Pluggable Transport To Parent Process Communication
+
+ All Pluggable Transport Proxies communicate to the parent process
+ via writing NL-terminated lines to stdout. The line metaformat is:
+
+ <Line> ::= <Keyword> <OptArgs> <NL>
+ <Keyword> ::= <KeywordChar> | <Keyword> <KeywordChar>
+ <KeywordChar> ::= <any US-ASCII alphanumeric, dash, and underscore>
+ <OptArgs> ::= <Args>*
+ <Args> ::= <SP> <ArgChar> | <Args> <ArgChar>
+ <ArgChar> ::= <any US-ASCII character but NUL or NL>
+ <SP> ::= <US-ASCII whitespace symbol (32)>
+ <NL> ::= <US-ASCII newline (line feed) character (10)>
+
+ The parent process MUST ignore lines received from PT proxies with
+ unknown keywords.
+
+3.3.1. Common Messages
+
+ When a PT proxy first starts up, it must determine which version
+ of the Pluggable Transports Specification to use to configure
+ itself.
+
+ It does this via the "TOR_PT_MANAGED_TRANSPORT_VER" (3.2.1)
+ environment variable which contains all of the versions supported
+ by the application.
+
+ Upon determining the version to use, or lack thereof, the PT
+ proxy responds with one of two messages.
+
+ VERSION-ERROR <ErrorMessage>
+
+ The "VERSION-ERROR" message is used to signal that there was
+ no compatible Pluggable Transport Specification version
+ present in the "TOR_PT_MANAGED_TRANSPORT_VER" list.
+
+ The <ErrorMessage> SHOULD be set to "no-version" for
+ historical reasons but MAY be set to a useful error message
+ instead.
+
+ PT proxies MUST terminate after outputting a "VERSION-ERROR"
+ message.
+
+ Example:
+
+ VERSION-ERROR no-version
+
+ VERSION <ProtocolVersion>
+
+ The "VERSION" message is used to signal the Pluggable Transport
+ Specification version (as in "TOR_PT_MANAGED_TRANSPORT_VER")
+ that the PT proxy will use to configure it's transports and
+ communicate with the parent process.
+
+ The version for the environment values and reply messages
+ specified by this document is "1".
+
+ PT proxies MUST either report an error and terminate, or output
+ a "VERSION" message before moving on to client/server proxy
+ initialization and configuration.
+
+ Example:
+
+ VERSION 1
+
+ After version negotiation has been completed the PT proxy must
+ then validate that all of the required environment variables are
+ provided, and that all of the configuration values supplied are
+ well formed.
+
+ At any point, if there is an error encountered related to
+ configuration supplied via the environment variables, it MAY
+ respond with an error message and terminate.
+
+ ENV-ERROR <ErrorMessage>
+
+ The "ENV-ERROR" message is used to signal the PT proxy's
+ failure to parse the configuration environment variables (3.2).
+
+ The <ErrorMessage> SHOULD consist of a useful error message
+ that can be used to diagnose and correct the root cause of
+ the failure.
+
+ PT proxies MUST terminate after outputting a "ENV-ERROR"
+ message.
+
+ Example:
+
+ ENV-ERROR No TOR_PT_AUTH_COOKIE_FILE when TOR_PT_EXTENDED_SERVER_PORT set
+
+3.3.2. Pluggable Transport Client Messages
+
+ After negotiating the Pluggable Transport Specification version,
+ PT client proxies MUST first validate "TOR_PT_PROXY" (3.2.2) if
+ it is set, before initializing any transports.
+
+ Assuming that an upstream proxy is provided, PT client proxies
+ MUST respond with a message indicating that the proxy is valid,
+ supported, and will be used OR a failure message.
+
PROXY DONE
- On failure it writes:
- PROXY-ERROR <errormessage>
-2.2.1.0.1. Client PT configuration (CMETHOD lines)
+ The "PROXY DONE" message is used to signal the PT proxy's
+ acceptance of the upstream proxy specified by "TOR_PT_PROXY".
- Client PTs report their transports via zero or more CMETHOD lines,
- with the following format:
- CMETHOD <transport> socks4/socks5 <address:port>
- For example:
- CMETHOD trebuchet socks5 127.0.0.1:19999
+ PROXY-ERROR <ErrorMessage>
- The 'address:port' component of a CMETHOD line is the IP address and
- TCP port of the SOCKS proxy server the client PT has exposed.
+ The "PROXY-ERROR" message is used to signal that the upstream
+ proxy is malformed/unsupported or otherwise unusable.
- If the PT tries to supply a client method but can not for some
- reason, it MUST write:
- CMETHOD-ERROR <methodname> <errormessage>
- For example:
- CMETHOD-ERROR trebuchet no rocks available
+ PT proxies MUST terminate immediately after outputting a
+ "PROXY-ERROR" message.
- After it is finished communicating all of the client methods it
- provides, the proxy MUST print a single "CMETHODS DONE" line. At this
- point the managed proxy configuration is complete.
+ Example:
-2.2.1.1. Server PT behaviour (SMETHOD lines)
+ PROXY-ERROR SOCKS 4 upstream proxies unsupported.
- Server PTs report their transports via zero or more SMETHOD lines,
- with the following format:
- SMETHOD <methodname> <address:port> [options]
+ After the upstream proxy (if any) is configured, PT clients then
+ iterate over the requested transports in "TOR_PT_CLIENT_TRANSPORTS"
+ and initialize the listeners.
- The 'address:port' component of a SMETHOD line is the IP address and
- port where the server PT is listening for incoming client connections.
- The optional 'options' component is a list of space-separated K:V
- flags that Tor should know about. Recognised options are:
+ For each transport initialized, the PT proxy reports the listener
+ status back to the parent via messages to stdout.
- - ARGS:K=V,K=V,K=V
+ CMETHOD <transport> <'socks4','socks5'> <address:port>
- If this option is set, the K=V arguments are added to Tor's
- extrainfo document. Equal signs and commas must be escaped
- with a backslash.
+ The "CMETHOD" message is used to signal that a requested
+ PT transport has been launched, the protocol which the parent
+ should use to make outgoing connections, and the IP address
+ and port that the PT transport's forward proxy is listening on.
- If the PT tries to supply a server method but can not for some
- reason, it MUST write:
- SMETHOD-ERROR <methodname> <errormessage>
+ Example:
+
+ CMETHOD trebuchet socks5 127.0.0.1:19999
+
+ CMETHOD-ERROR <transport> <ErrorMessage>
+
+ The "CMETHOD-ERROR" message is used to signal that
+ requested PT transport was unable to be launched.
+
+ Example:
+
+ CMETHOD-ERROR trebuchet no rocks available
+
+ Once all PT transports have been initialized (or have failed), the
+ PT proxy MUST send a final message indicating that it has finished
+ initializing.
+
+ CMETHODS DONE
+
+ The "CMETHODS DONE" message signals that the PT proxy has
+ finished initializing all of the transports that it is capable
+ of handling.
+
+ Upon sending the "CMETHODS DONE" message, the PT proxy
+ initialization is complete.
+
+ Notes:
+
+ - Unknown transports in "TOR_PT_CLIENT_TRANSPORTS" are ignored
+ entirely, and MUST NOT result in a "CMETHOD-ERROR" message.
+ Thus it is entirely possible for a given PT proxy to
+ immediately output "CMETHODS DONE".
+
+ - Parent processes MUST handle "CMETHOD"/"CMETHOD-ERROR"
+ messages in any order, regardless of ordering in
+ "TOR_PT_CLIENT_TRANSPORTS".
+
+3.3.3. Pluggable Transport Server Messages
+
+ PT server reverse proxies iterate over the requested transports
+ in "TOR_PT_CLIENT_TRANSPORTS" and initialize the listeners.
+
+ For each transport initialized, the PT proxy reports the listener
+ status back to the parent via messages to stdout.
+
+ SMETHOD <transport> <address:port> [options]
+
+ The "SMETHOD" message is used to signal that a requested
+ PT transport has been launched, the protocol which will be
+ used to handle incoming connections, and the IP address and
+ port that clients should use to reach the reverse-proxy.
+
+ If there is a specific <address:port> provided for a given
+ PT transport via "TOR_PT_SERVER_BINDADDR", the transport
+ MUST be initialized using that as the server address.
+
+ The OPTIONAL 'options' field is used to pass additional
+ per-transport information back to the parent process.
+
+ The currently recognized 'options' are:
+
+ ARGS:[<Key>=<Value>,]+[<Key>=<Value>]
+
+ The "ARGS" option is used to pass additional key/value
+ formatted information that clients will require to use
+ the reverse proxy.
+
+ Equal signs and commas MUST be escaped with a backslash.
+
+ Tor: The ARGS are included in the transport line of the
+ Bridge's extra-info document.
+
+ Examples:
+
+ SMETHOD trebuchet 198.51.100.1:19999
+ SMETHOD rot_by_N 198.51.100.1:2323 ARGS:N=13
+
+ SMETHOD-ERROR <transport> <ErrorMessage>
+
+ The "SMETHOD-ERROR" message is used to signal that
+ requested PT transport reverse proxy was unable to be
+ launched.
+
+ Example:
+
+ SMETHOD-ERROR trebuchet no cows available
+
+ Once all PT transports have been initialized (or have failed), the
+ PT proxy MUST send a final message indicating that it has finished
+ initializing.
+
+ SMETHODS DONE
- After it is finished communicating all of the server methods it
- provides, the PT should print a single "SMETHODS DONE" line. At
- this point the server PT configuration is complete.
+ The "SMETHODS DONE" message signals that the PT proxy has
+ finished initializing all of the transports that it is capable
+ of handling.
-2.2.2. Managed proxy protocol behaviour
+ Upon sending the "SMETHODS DONE" message, the PT proxy
+ initialization is complete.
- This section specifies some behaviours that Tor and PTs SHOULD abide
- too while performing the managed proxy protocol:
+3.4. Pluggable Transport Shutdown
- SMETHOD and CMETHOD lines may be interspersed, to allow the proxies to
- report methods as they become available, even when some methods may
- require probing the network, connecting to external peers, etc before
- they are set up.
+ The recommended way for Pluggable Transport using applications and
+ Pluggable Transports to handle graceful shutdown is as follows.
- The proxy SHOULD NOT tell Tor about a server or client method
- unless it is actually open and ready to use.
+ - (Parent) Set "TOR_PT_EXIT_ON_STDIN_CLOSE" (3.2.1) when
+ launching the PT proxy, to indicate that stdin will be used
+ for graceful shutdown notification.
- Tor clients SHOULD NOT use any method from a client proxy or
- advertise any method from a server proxy UNLESS it is listed as a
- possible method for that proxy in torrc, and it is listed by the
- proxy as a method it supports.
+ - (Parent) When the time comes to terminate the PT proxy:
- The managed proxy configuration protocol version defined in this
- section is "1".
- So, for example, if tor supports this configuration protocol it
- should set the environment variable:
- TOR_PT_MANAGED_TRANSPORT_VER=1
+ 1. Close the PT proxy's stdin.
+ 2. Wait for a "reasonable" amount of time for the PT to exit.
+ 3. Attempt to use OS specific mechanisms to cause graceful
+ PT shutdown (eg: 'SIGTERM')
+ 4. Use OS specific mechanisms to force terminate the PT
+ (eg: 'SIGKILL', 'ProccessTerminate()').
+
+ - PT proxies SHOULD monitor stdin, and exit gracefully when
+ it is closed, if the parent supports that behavior.
+
+ - PT proxies SHOULD handle OS specific mechanisms to gracefully
+ terminate (eg: Install a signal handler on 'SIGTERM' that
+ causes cleanup and a graceful shutdown if able).
+
+ - PT proxies SHOULD attempt to detect when the parent has
+ terminated (eg: via detecting that it's parent process ID haso
+ changed on U*IX systems), and gracefully terminate.
+
+3.5. Pluggable Transport Client Per-Connection Arguments
+
+ Certain PT transport protocols require that the client provides
+ per-connection arguments when making outgoing connections. On
+ the server side, this is handled by the "ARGS" optional argument
+ as part of the "SMETHOD" message.
+
+ On the client side, arguments are passed via the authentication
+ fields that are part of the SOCKS protocol.
+
+ First the "<Key>=<Value>" formatted arguments MUST be escaped,
+ such that all backslash, equal sign, and semicolon characters
+ are escaped with a backslash.
+
+ Second, all of the escaped are concatenated together.
+
+ Example:
+
+ shared-secret=rahasia;secrets-file=/tmp/blob
+
+ Lastly the arguments are transmitted when making the outgoing
+ connection using the authentication mechanism specific to the
+ SOCKS protocol version.
+
+ - In the case of SOCKS 4, the concatenated argument list is
+ transmitted in the "USERID" field of the "CONNECT" request.
+
+ - In the case of SOCKS 5, the parent process must negotiate
+ "Username/Password" authentication [RFC1929], and transmit
+ the arguments encoded in the "UNAME" and "PASSWD" fields.
+
+ If the encoded argument list is less than 255 bytes in
+ length, the "PLEN" field must be set to "1" and the "PASSWD"
+ field must contain a single NUL character.
+
+4. Anonymity Considerations
+
+ When designing and implementing a Pluggable Transport, care
+ should be taken to preserve the privacy of clients and to avoid
+ leaking personally identifying information.
+
+ Examples of client related considerations are:
+
+ - Not logging client IP addresses to disk.
+
+ - Not leaking DNS addresses except when necessary.
+
+ - Ensuring that "TOR_PT_PROXY"'s "fail closed" behavior is
+ implemented correctly.
+
+ Additionally, certain obfuscation mechanisms rely on information
+ such as the server IP address/port being confidential, so clients
+ also need to take care to preserve server side information
+ confidential when applicable.
+
+5. References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC1928] Leech, M., Ganis, M., Lee, Y., Kuris, R.,
+ Koblas, D., Jones, L., "SOCKS Protocol Version 5",
+ RFC 1928, March 1996.
+
+ [EXTORPORT] Kadianakis, G., Mathewson, N., "Extended ORPort and
+ TransportControlPort", Tor Proposal 196, March 2012.
+
+ [RFC3986] Berners-Lee, T., Fielding, R., Masinter, L., "Uniform
+ Resource Identifier (URI): Generic Syntax", RFC 3986,
+ January 2005.
+
+ [RFC1929] Leech, M., "Username/Password Authentication for
+ SOCKS V5", RFC 1929, March 1996.
+
+6. Acknowledgments
+
+ This specification draws heavily from prior versions done by Jacob
+ Appelbaum, Nick Mathewson, and George Kadianakis.
+
+Appendix A. Example Client Pluggable Transport Session
+
+ Environment variables:
+
+ TOR_PT_MANAGED_TRANSPORT_VER=1
+ TOR_PT_STATE_LOCATION=/var/lib/tor/pt_state/
+ TOR_PT_EXIT_ON_STDIN_CLOSE=1
+ TOR_PT_PROXY=socks5://127.0.0.1:8001
+ TOR_PT_CLIENT_TRANSPORTS=obfs3,obfs4
+
+ Messages the PT Proxy writes to stdin:
+
+ VERSION 1
+ PROXY DONE
+ CMETHOD obfs3 socks5 127.0.0.1:32525
+ CMETHOD obfs4 socks5 127.0.0.1:37347
+ CMETHODS DONE
-2.3. Extended ORPort [EXTORPORT]
+Appendix B. Example Server Pluggable Transport Session
- Server-side PTs SHOULD pass additional information about their clients
- to Tor for statistics gathering. This is done using the Extended
- ORPort protocol, which is a variant of the ORPort with an extra
- metadata channel.
+ Environment variables:
- For example, PTs are expected to use the Extended ORPort metadata
- channel to inform Tor about the PT used in each connection, so that
- Tor can keep track on the number of connections per PT.
+ TOR_PT_MANAGED_TRANSPORT_VER=1
+ TOR_PT_STATE_LOCATION=/var/lib/tor/pt_state
+ TOR_PT_EXIT_ON_STDIN_CLOSE=1
+ TOR_PT_SERVER_TRANSPORTS=obfs3,obfs4
+ TOR_PT_SERVER_BINDADDR=obfs3-198.51.100.1:1984
- The Extended ORPort protocol is specified in proposal
- 196-transport-control-ports.txt.
+ Messages the PT Proxy writes to stdin:
-TODO: Managed proxy protocol test vectors
+ VERSION 1
+ SMETHOD obfs3 198.51.100.1:1984
+ SMETHOD obfs4 198.51.100.1:43734 ARGS:cert=HszPy3vWfjsESCEOo9ZBkRv6zQ/1mGHzc8arF0y2SpwFr3WhsMu8rK0zyaoyERfbz3ddFw,iat-mode=0
+ SMETHODS DONE
1
0